// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. artifact-probe module for scripts/src/artifact-registry.ts. // Moved mechanically from scripts/src/artifact-registry.ts:2391-2578 for #903. import { createHash } from "node:crypto"; import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { runCommand, type CommandResult } from "../command"; import { readConfig, type UniDeskConfig, repoRoot, rootPath } from "../config"; import { startJob } from "../jobs"; import { compareDeployJsonExecutorMirrors, deployJsonCommitImage, deployJsonDriftResult, deployJsonSourceOfTruth, hasDeployJsonExecutorContract, k3sManifestExecutorMirror, parseDeployJsonServiceContractBase64, readDeployJsonServiceContractFromFile, type DeployJsonExecutorMirror, type DeployJsonServiceContract, } from "../deploy-json-contract"; import { d601K3sGuardShellLines } from "../d601-k3s-guard"; import { composeRuntimeEnvValue } from "../runtime-env"; import type { ArtifactConsumerSpec, ArtifactConsumerTarget, ArtifactRegistryOptions } from "./types"; import { base64, d601K3sGuardScript, shellQuote } from "./bundle"; import { artifactImageRef, deployRefFor, sourceRepoFor } from "./consumer"; export function registryArtifactProbeScript(options: ArtifactRegistryOptions, spec: ArtifactConsumerSpec, commit: string): string { const sourceImage = artifactImageRef(options, spec, commit); return [ "set -euo pipefail", `registry_image=${shellQuote(sourceImage)}`, `manifest_url=${shellQuote(`http://127.0.0.1:${options.port}/v2/${spec.registryRepository}/manifests/${commit}`)}`, "headers=$(mktemp /tmp/unidesk-artifact-manifest.XXXXXX.headers)", "trap 'rm -f \"$headers\"' EXIT", "curl -fsSI -H 'Accept: application/vnd.docker.distribution.manifest.v2+json' -D \"$headers\" -o /dev/null \"$manifest_url\"", "manifest_digest=$(awk 'BEGIN{IGNORECASE=1} /^Docker-Content-Digest:/ {gsub(/\\r/, \"\", $2); print $2; exit}' \"$headers\")", "printf 'registry_image=%s\\nmanifest_url=%s\\nmanifest_digest=%s\\n' \"$registry_image\" \"$manifest_url\" \"$manifest_digest\"", ].join("\n"); } export function registryArtifactMissingMessage(spec: ArtifactConsumerSpec): string { return `${spec.serviceId} image artifact is missing from D601 registry; run CI artifact publication first`; } export function verifyLocalArtifactLabels( localLoadedImage: string, spec: ArtifactConsumerSpec, commit: string, sourceRepo: string, ): Record | null { const inspectPulled = runCommand(["docker", "image", "inspect", localLoadedImage, "--format", "{{json .Config.Labels}}"], repoRoot); const labelCommit = runCommand(["docker", "image", "inspect", localLoadedImage, "--format", "{{ index .Config.Labels \"unidesk.ai/source-commit\" }}"], repoRoot); const labelService = runCommand(["docker", "image", "inspect", localLoadedImage, "--format", "{{ index .Config.Labels \"unidesk.ai/service-id\" }}"], repoRoot); const labelRepo = runCommand(["docker", "image", "inspect", localLoadedImage, "--format", "{{ index .Config.Labels \"unidesk.ai/source-repo\" }}"], repoRoot); const labelDockerfile = runCommand(["docker", "image", "inspect", localLoadedImage, "--format", "{{ index .Config.Labels \"unidesk.ai/dockerfile\" }}"], repoRoot); const observed = { commit: labelCommit.stdout.trim(), serviceId: labelService.stdout.trim(), sourceRepo: labelRepo.stdout.trim(), dockerfile: labelDockerfile.stdout.trim(), labels: inspectPulled.stdout.trim(), }; const ok = observed.commit === commit && observed.serviceId === spec.serviceId && observed.sourceRepo === sourceRepo && observed.dockerfile === spec.dockerfile; if (ok) return null; return { ok: false, step: "image-label-verify", expected: { commit, serviceId: spec.serviceId, sourceRepo, dockerfile: spec.dockerfile }, observed, }; } export function d601DevFrontendAuthPatchScript(config: UniDeskConfig): string { const sshClientToken = composeRuntimeEnvValue("UNIDESK_SSH_CLIENT_TOKEN"); if (sshClientToken === null) throw new Error("UNIDESK_SSH_CLIENT_TOKEN must be present in .state/docker-compose.env before deploying dev frontend"); const sshClientRouteAllowlist = composeRuntimeEnvValue("UNIDESK_SSH_CLIENT_ROUTE_ALLOWLIST") ?? "G14,G14:*,D601,D601:*"; const secretData = { AUTH_USERNAME: base64(config.auth.username), AUTH_PASSWORD: base64(config.auth.password), SESSION_SECRET: base64(config.auth.sessionSecret), UNIDESK_SSH_CLIENT_TOKEN: base64(sshClientToken), }; const configData = { SESSION_TTL_SECONDS: String(config.auth.sessionTtlSeconds), UNIDESK_SSH_CLIENT_ROUTE_ALLOWLIST: sshClientRouteAllowlist, }; return [ d601K3sGuardScript(), `secret_patch=${shellQuote(JSON.stringify({ data: secretData }))}`, `config_patch=${shellQuote(JSON.stringify({ data: configData }))}`, "kubectl -n unidesk-dev patch secret unidesk-dev-runtime-secrets --type merge -p \"$secret_patch\"", "kubectl -n unidesk-dev patch configmap unidesk-dev-runtime-config --type merge -p \"$config_patch\"", "echo artifact_cd_dev_frontend_auth_synced=ok", ].join("\n"); } export function composeArtifactEnvValues(spec: ArtifactConsumerSpec, target: ArtifactConsumerTarget, options: ArtifactRegistryOptions, commit: string): Record { if (target.compose === undefined) throw new Error(`${spec.serviceId} missing compose artifact consumer config`); const prefix = target.compose.deployEnvPrefix; return { [`${prefix}_SERVICE_ID`]: spec.serviceId, [`${prefix}_REF`]: deployRefFor(options, spec), [`${prefix}_REPO`]: sourceRepoFor(options, spec), [`${prefix}_COMMIT`]: commit, [`${prefix}_REQUESTED_COMMIT`]: commit, }; } export function syntheticComposeHealthDeployScript(compose: NonNullable, 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", ]; }