补强静态发布安全边界
This commit is contained in:
@@ -139,7 +139,7 @@ async function readProductOverview(projectPath: string): Promise<string> {
|
||||
async function resolveProjectProgressIdentity(
|
||||
project: OpencodeProject,
|
||||
): Promise<ProjectProgressIdentity> {
|
||||
const binding = await readWorksSubmissionBinding(project.path);
|
||||
const binding = await readWorksSubmissionBinding(project.path, project.id);
|
||||
if (binding?.status === 'submitted' && binding.app_id) {
|
||||
return { projectType: 'server', projectKey: binding.app_id };
|
||||
}
|
||||
|
||||
@@ -47,15 +47,58 @@ function readString(value: unknown): string | null {
|
||||
function parseCurrentRecord(value: unknown): WorksSubmissionBindingRecord | null {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
||||
const record = value as Record<string, unknown>;
|
||||
if (
|
||||
record.schema_version !== WORKS_SUBMISSION_BINDING_SCHEMA_VERSION
|
||||
|| (record.status !== 'submitted' && record.status !== 'legacy_retired')
|
||||
) return null;
|
||||
if (record.schema_version !== WORKS_SUBMISSION_BINDING_SCHEMA_VERSION) return null;
|
||||
const projectId = readString(record.project_id);
|
||||
const requestedAt = readString(record.requested_at);
|
||||
const updatedAt = readString(record.updated_at);
|
||||
if (!projectId || !requestedAt || !updatedAt) return null;
|
||||
return record as WorksSubmissionBindingRecord;
|
||||
|
||||
if (record.status === 'submitted') {
|
||||
const appId = readString(record.app_id);
|
||||
const versionId = readString(record.version_id);
|
||||
const versionName = readString(record.version_name);
|
||||
const reviewStatus = record.review_status === undefined
|
||||
? null
|
||||
: readString(record.review_status);
|
||||
const zipSha256 = record.zip_sha256 === undefined
|
||||
? null
|
||||
: readString(record.zip_sha256);
|
||||
if (
|
||||
!appId
|
||||
|| !versionId
|
||||
|| !versionName
|
||||
|| (record.review_status !== undefined && !reviewStatus)
|
||||
|| (record.zip_sha256 !== undefined && (!zipSha256 || !/^[a-f0-9]{64}$/i.test(zipSha256)))
|
||||
) return null;
|
||||
return {
|
||||
schema_version: WORKS_SUBMISSION_BINDING_SCHEMA_VERSION,
|
||||
project_id: projectId,
|
||||
status: 'submitted',
|
||||
requested_at: requestedAt,
|
||||
updated_at: updatedAt,
|
||||
app_id: appId,
|
||||
version_id: versionId,
|
||||
version_name: versionName,
|
||||
...(reviewStatus ? { review_status: reviewStatus } : {}),
|
||||
...(zipSha256 ? { zip_sha256: zipSha256.toLowerCase() } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
const message = readString(record.message);
|
||||
if (
|
||||
record.status !== 'legacy_retired'
|
||||
|| record.error_code !== 'LEGACY_AUTO_DEPLOY_RETIRED'
|
||||
|| !message
|
||||
) return null;
|
||||
return {
|
||||
schema_version: WORKS_SUBMISSION_BINDING_SCHEMA_VERSION,
|
||||
project_id: projectId,
|
||||
status: 'legacy_retired',
|
||||
requested_at: requestedAt,
|
||||
updated_at: updatedAt,
|
||||
error_code: 'LEGACY_AUTO_DEPLOY_RETIRED',
|
||||
message,
|
||||
};
|
||||
}
|
||||
|
||||
function parseLegacyRecord(value: unknown): LegacyBindingRecord | null {
|
||||
@@ -73,23 +116,25 @@ function parseLegacyRecord(value: unknown): LegacyBindingRecord | null {
|
||||
|
||||
function migrateLegacyRecord(record: LegacyBindingRecord): WorksSubmissionBindingRecord {
|
||||
const now = new Date().toISOString();
|
||||
if (
|
||||
record.status === 'submitted'
|
||||
&& readString(record.app_id)
|
||||
&& readString(record.version_id)
|
||||
&& readString(record.version_name)
|
||||
) {
|
||||
const appId = readString(record.app_id);
|
||||
const versionId = readString(record.version_id);
|
||||
const versionName = readString(record.version_name);
|
||||
if (record.status === 'submitted' && appId && versionId && versionName) {
|
||||
const reviewStatus = readString(record.review_status);
|
||||
const zipSha256 = readString(record.zip_sha256);
|
||||
return {
|
||||
schema_version: WORKS_SUBMISSION_BINDING_SCHEMA_VERSION,
|
||||
project_id: record.project_id,
|
||||
status: 'submitted',
|
||||
requested_at: record.requested_at,
|
||||
updated_at: now,
|
||||
app_id: record.app_id,
|
||||
version_id: record.version_id,
|
||||
version_name: record.version_name,
|
||||
...(readString(record.review_status) ? { review_status: record.review_status } : {}),
|
||||
...(readString(record.zip_sha256) ? { zip_sha256: record.zip_sha256 } : {}),
|
||||
app_id: appId,
|
||||
version_id: versionId,
|
||||
version_name: versionName,
|
||||
...(reviewStatus ? { review_status: reviewStatus } : {}),
|
||||
...(zipSha256 && /^[a-f0-9]{64}$/i.test(zipSha256)
|
||||
? { zip_sha256: zipSha256.toLowerCase() }
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -120,6 +165,7 @@ async function persistRecord(
|
||||
|
||||
export async function readWorksSubmissionBinding(
|
||||
projectPath: string,
|
||||
expectedProjectId?: string,
|
||||
): Promise<WorksSubmissionBindingRecord | null> {
|
||||
let parsed: unknown;
|
||||
try {
|
||||
@@ -132,9 +178,9 @@ export async function readWorksSubmissionBinding(
|
||||
}
|
||||
|
||||
const current = parseCurrentRecord(parsed);
|
||||
if (current) return current;
|
||||
if (current) return !expectedProjectId || current.project_id === expectedProjectId ? current : null;
|
||||
const legacy = parseLegacyRecord(parsed);
|
||||
if (!legacy) return null;
|
||||
if (!legacy || (expectedProjectId && legacy.project_id !== expectedProjectId)) return null;
|
||||
return persistRecord(projectPath, migrateLegacyRecord(legacy));
|
||||
}
|
||||
|
||||
@@ -162,13 +208,13 @@ export function createWorksSubmissionBindingStore(projectStore: ProjectStore) {
|
||||
|
||||
async function get(projectId: string): Promise<WorksSubmissionBindingRecord | null> {
|
||||
const project = (await projectStore.listProjects()).find((item) => item.id === projectId);
|
||||
return project ? readWorksSubmissionBinding(project.path) : null;
|
||||
return project ? readWorksSubmissionBinding(project.path, project.id) : null;
|
||||
}
|
||||
|
||||
async function start(): Promise<void> {
|
||||
for (const project of await projectStore.listProjects()) {
|
||||
try {
|
||||
await readWorksSubmissionBinding(project.path);
|
||||
await readWorksSubmissionBinding(project.path, project.id);
|
||||
} catch (error) {
|
||||
logger.warn(`[works-submission-binding] Failed to migrate ${project.id}`, error);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user