test: add todo-note runtime artifact proof

This commit is contained in:
Codex
2026-05-21 13:32:01 +00:00
parent fc87e680e4
commit 5cb5cc1b43
7 changed files with 292 additions and 7 deletions
+108 -2
View File
@@ -159,6 +159,7 @@ interface ArtifactConsumerTarget {
projectHint?: string;
requiredRuntimeSecrets?: RuntimeSecretRequirement[];
authHealthGate?: AuthHealthGate;
syntheticHealthDeployProof?: SyntheticHealthDeployProof;
};
k3s?: {
namespace: string;
@@ -184,6 +185,11 @@ interface AuthHealthGate {
recoveryHint: string;
}
interface SyntheticHealthDeployProof {
kind: "compose-container-runtime-metadata";
description: string;
}
interface ComposeArtifactRuntime {
workDir: string;
composeFile: string;
@@ -230,8 +236,13 @@ export interface RuntimeSecretContract {
dryRunDisposition: "not-required" | "ready-for-live-apply" | "secret-source-blocked";
}
const todoNoteSyntheticHealthDeployProof: SyntheticHealthDeployProof = {
kind: "compose-container-runtime-metadata",
description: "todo-note /api/health does not natively expose deploy metadata, so the artifact consumer synthesizes health.deploy from the recreated container's UNIDESK_DEPLOY_* env and verifies it against image/container labels.",
};
function todoNoteHealthProbeCommand(): string {
return "bun -e \"fetch('http://127.0.0.1:4211/api/health').then(async r=>{const text=await r.text(); let body; try{body=JSON.parse(text)}catch{body={ok:r.ok,raw:text}}; const deploy=body.deploy&&typeof body.deploy==='object'&&!Array.isArray(body.deploy)?body.deploy:{}; body.deploy={...deploy,serviceId:deploy.serviceId||process.env.UNIDESK_DEPLOY_SERVICE_ID||'todo-note',ref:deploy.ref||process.env.UNIDESK_DEPLOY_REF||'',repo:deploy.repo||process.env.UNIDESK_DEPLOY_REPO||'',commit:deploy.commit||process.env.UNIDESK_DEPLOY_COMMIT||'',requestedCommit:deploy.requestedCommit||process.env.UNIDESK_DEPLOY_REQUESTED_COMMIT||''}; console.log(JSON.stringify(body)); process.exit(r.ok?0:1)}).catch(e=>{console.error(e); process.exit(1)})\"";
return "bun -e \"fetch('http://127.0.0.1:4211/api/health').then(async r=>{const text=await r.text(); let body; try{body=JSON.parse(text)}catch{body={ok:r.ok,raw:text}}; console.log(JSON.stringify(body)); process.exit(r.ok?0:1)}).catch(e=>{console.error(e); process.exit(1)})\"";
}
export const baiduNetdiskRuntimeSecretRequirements: RuntimeSecretRequirement[] = [
@@ -777,6 +788,7 @@ const artifactConsumerSpecs: Record<string, ArtifactConsumerSpec> = {
deployEnvPrefix: "UNIDESK_TODO_NOTE_DEPLOY",
healthProbeCommand: todoNoteHealthProbeCommand(),
requireHealthCommit: true,
syntheticHealthDeployProof: todoNoteSyntheticHealthDeployProof,
},
},
prod: {
@@ -789,6 +801,7 @@ const artifactConsumerSpecs: Record<string, ArtifactConsumerSpec> = {
deployEnvPrefix: "UNIDESK_TODO_NOTE_DEPLOY",
healthProbeCommand: todoNoteHealthProbeCommand(),
requireHealthCommit: true,
syntheticHealthDeployProof: todoNoteSyntheticHealthDeployProof,
},
},
},
@@ -2166,6 +2179,70 @@ function composeArtifactEnvValues(spec: ArtifactConsumerSpec, target: ArtifactCo
};
}
function syntheticComposeHealthDeployScript(compose: NonNullable<ArtifactConsumerTarget["compose"]>, commit: string, sourceRepo: string): string[] {
if (compose.syntheticHealthDeployProof === undefined) return [];
const prefix = compose.deployEnvPrefix;
const envKeys = [
"UNIDESK_DEPLOY_SERVICE_ID",
"UNIDESK_DEPLOY_REF",
"UNIDESK_DEPLOY_REPO",
"UNIDESK_DEPLOY_COMMIT",
"UNIDESK_DEPLOY_REQUESTED_COMMIT",
`${prefix}_SERVICE_ID`,
`${prefix}_REF`,
`${prefix}_REPO`,
`${prefix}_COMMIT`,
`${prefix}_REQUESTED_COMMIT`,
];
const envKeysJson = JSON.stringify(envKeys);
return [
"runtime_metadata_json=$(docker inspect \"$cid\" --format '{{json .Config.Env}}')",
"container_label_commit=$(docker inspect -f '{{ index .Config.Labels \"unidesk.ai/deploy-commit\" }}' \"$cid\")",
"container_label_requested_commit=$(docker inspect -f '{{ index .Config.Labels \"unidesk.ai/deploy-requested-commit\" }}' \"$cid\")",
"container_label_repo=$(docker inspect -f '{{ index .Config.Labels \"unidesk.ai/deploy-repo\" }}' \"$cid\")",
"container_label_ref=$(docker inspect -f '{{ index .Config.Labels \"unidesk.ai/deploy-ref\" }}' \"$cid\")",
`python3 - "$health_json" "$runtime_metadata_json" ${shellQuote(envKeysJson)} ${shellQuote(prefix)} ${shellQuote(commit)} ${shellQuote(sourceRepo)} "$actual_commit" "$actual_service" "$actual_repo" "$container_label_commit" "$container_label_requested_commit" "$container_label_repo" "$container_label_ref" <<'PY'`,
"import json, sys",
"path, env_json, keys_json, prefix, expected_commit, expected_repo, image_commit, image_service, image_repo, label_commit, label_requested_commit, label_repo, label_ref = sys.argv[1:]",
"body = json.load(open(path, encoding='utf-8'))",
"env_items = json.loads(env_json)",
"allow = set(json.loads(keys_json))",
"env = {}",
"for item in env_items:",
" if not isinstance(item, str) or '=' not in item:",
" continue",
" key, value = item.split('=', 1)",
" if key in allow:",
" env[key] = value",
"deploy = body.get('deploy') if isinstance(body, dict) and isinstance(body.get('deploy'), dict) else {}",
"synthetic = {",
" 'serviceId': deploy.get('serviceId') or env.get('UNIDESK_DEPLOY_SERVICE_ID') or env.get(prefix + '_SERVICE_ID') or image_service,",
" 'ref': deploy.get('ref') or env.get('UNIDESK_DEPLOY_REF') or env.get(prefix + '_REF') or label_ref,",
" 'repo': deploy.get('repo') or env.get('UNIDESK_DEPLOY_REPO') or env.get(prefix + '_REPO') or label_repo or image_repo,",
" 'commit': deploy.get('commit') or env.get('UNIDESK_DEPLOY_COMMIT') or env.get(prefix + '_COMMIT') or label_commit or image_commit,",
" 'requestedCommit': deploy.get('requestedCommit') or env.get('UNIDESK_DEPLOY_REQUESTED_COMMIT') or env.get(prefix + '_REQUESTED_COMMIT') or label_requested_commit,",
"}",
"body['deploy'] = synthetic",
"body['deployProof'] = {",
" 'kind': 'compose-container-runtime-metadata',",
" 'sources': ['service-health', 'container-env', 'container-labels', 'image-labels'],",
" 'sourceDirectoryUsed': False,",
" 'envKeysUsed': sorted([key for key in env if key.startswith('UNIDESK_DEPLOY_') or key.startswith(prefix + '_')]),",
"}",
"if synthetic.get('commit') != expected_commit or synthetic.get('requestedCommit') != expected_commit:",
" raise SystemExit('synthetic deploy commit mismatch: ' + json.dumps(synthetic, sort_keys=True))",
"if synthetic.get('repo') != expected_repo:",
" raise SystemExit('synthetic deploy repo mismatch: ' + json.dumps(synthetic, sort_keys=True))",
"if synthetic.get('serviceId') != image_service:",
" raise SystemExit('synthetic deploy service mismatch: ' + json.dumps(synthetic, sort_keys=True))",
"with open(path, 'w', encoding='utf-8') as handle:",
" json.dump(body, handle, separators=(',', ':'))",
" handle.write('\\n')",
"print('synthetic_health_deploy_proof=compose-container-runtime-metadata sourceDirectoryUsed=false')",
"PY",
];
}
async function deployComposeArtifactNow(options: ArtifactRegistryOptions, spec: ArtifactConsumerSpec, target: ArtifactConsumerTarget): Promise<Record<string, unknown>> {
const commit = options.commit;
if (commit === null) throw new Error("artifact-registry deploy-service requires --commit <full-sha>");
@@ -2202,6 +2279,7 @@ async function deployComposeArtifactNow(options: ArtifactRegistryOptions, spec:
return { ok: false, serviceId: spec.serviceId, error: "D601 artifact registry is not healthy", health };
}
const sourceImage = artifactImageRef(options, spec, commit);
const sourceRepo = sourceRepoFor(options, spec);
const composeImage = options.targetImage ?? target.targetImage;
const commitImage = `${composeImage}:${commit}`;
const registryProbe = runRemoteScript(options, registryArtifactProbeScript(options, spec, commit), Math.max(options.timeoutMs, 120_000));
@@ -2227,7 +2305,7 @@ async function deployComposeArtifactNow(options: ArtifactRegistryOptions, spec:
};
}
const localLoadedImage = sourceImage;
const labelFailure = verifyLocalArtifactLabels(localLoadedImage, spec, commit, sourceRepoFor(options, spec));
const labelFailure = verifyLocalArtifactLabels(localLoadedImage, spec, commit, sourceRepo);
if (labelFailure !== null) return { ...labelFailure, registryProbe: commandTail(registryProbe) };
const tag = runCommand(["docker", "tag", localLoadedImage, composeImage], repoRoot);
if (tag.exitCode !== 0 || tag.timedOut) {
@@ -2265,9 +2343,14 @@ async function deployComposeArtifactNow(options: ArtifactRegistryOptions, spec:
`cid=$(docker ps -q --filter label=com.docker.compose.project=${shellQuote(composeProject)} --filter label=com.docker.compose.service=${shellQuote(serviceName)} --filter label=com.docker.compose.oneoff=False | head -1)`,
"image_id=$(docker inspect -f '{{.Image}}' \"$cid\")",
"actual_commit=$(docker image inspect -f '{{ index .Config.Labels \"unidesk.ai/source-commit\" }}' \"$image_id\")",
"actual_service=$(docker image inspect -f '{{ index .Config.Labels \"unidesk.ai/service-id\" }}' \"$image_id\")",
"actual_repo=$(docker image inspect -f '{{ index .Config.Labels \"unidesk.ai/source-repo\" }}' \"$image_id\")",
`test "$actual_commit" = ${shellQuote(commit)}`,
`test "$actual_service" = ${shellQuote(spec.serviceId)}`,
`test "$actual_repo" = ${shellQuote(sourceRepo)}`,
`health_json=/tmp/unidesk-${safeName(spec.serviceId)}-health.json`,
`docker exec "$cid" sh -lc ${shellQuote(target.compose.healthProbeCommand)} > "$health_json"`,
...syntheticComposeHealthDeployScript(target.compose, commit, sourceRepo),
"cat \"$health_json\"",
...authHealthGateScript(target.compose.authHealthGate, "\"$health_json\""),
...(target.compose.requireHealthCommit ? [
@@ -2312,6 +2395,7 @@ async function deployComposeArtifactNow(options: ArtifactRegistryOptions, spec:
imageLabelCommit: commit,
serviceHealthCommit: target.compose.requireHealthCommit ? commit : "not-required",
serviceHealthRequestedCommit: target.compose.requireHealthCommit ? commit : "not-required",
runtimeProof: target.compose.syntheticHealthDeployProof === undefined ? "native-health" : target.compose.syntheticHealthDeployProof,
requiredRuntimeSecrets: secretPreflight.requirements,
runtimeSecrets,
authHealthGate: target.compose.authHealthGate === undefined ? "not-required" : {
@@ -2652,6 +2736,8 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
...(spec.kind === "d601-compose" ? ["running Compose container image label matches the requested commit"] : []),
verificationBlocked
? `blocked: ${spec.runtimeVerificationBlockReason}`
: target.compose.requireHealthCommit && target.compose.syntheticHealthDeployProof !== undefined
? `${spec.serviceId} runtime health proof synthesizes deploy.commit/deploy.requestedCommit from Compose container runtime metadata and verifies it against image/container labels, not source directory guesses`
: target.compose.requireHealthCommit
? `${spec.serviceId} runtime health probe succeeds and reports deploy.commit/deploy.requestedCommit matching the artifact commit`
: `${spec.serviceId} /health succeeds for the recreated container`,
@@ -2668,6 +2754,26 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
requiredAuthFields: target.compose.authHealthGate.requiredFields,
dryRunDisposition: "pending-live-check",
},
runtimeProof: target.compose.syntheticHealthDeployProof === undefined ? {
kind: "native-health-deploy-metadata",
sourceDirectoryUsed: false,
} : {
...target.compose.syntheticHealthDeployProof,
sourceDirectoryUsed: false,
sources: ["service-health", "container-env", "container-labels", "image-labels"],
requiredEnvKeys: [
"UNIDESK_DEPLOY_SERVICE_ID",
"UNIDESK_DEPLOY_REF",
"UNIDESK_DEPLOY_REPO",
"UNIDESK_DEPLOY_COMMIT",
"UNIDESK_DEPLOY_REQUESTED_COMMIT",
`${target.compose.deployEnvPrefix}_SERVICE_ID`,
`${target.compose.deployEnvPrefix}_REF`,
`${target.compose.deployEnvPrefix}_REPO`,
`${target.compose.deployEnvPrefix}_COMMIT`,
`${target.compose.deployEnvPrefix}_REQUESTED_COMMIT`,
],
},
rollback: rollbackInfo(spec, target, environment, commit),
};
}
+3
View File
@@ -1076,6 +1076,9 @@ function artifactConsumerPlanValidation(service: UniDeskMicroserviceConfig, envi
...base,
"recreates only the selected Compose service with --no-build --no-deps --force-recreate",
"verifies running image labels and private service health",
...(service.id === "todo-note" ? [
"todo-note runtime proof synthesizes health.deploy.commit/requestedCommit from Compose container env, container labels, and image labels; it does not infer commit from /root/todo_note or any source directory",
] : []),
];
}
return ["unsupported service remains blocked before source materialization or runtime mutation"];