import { spawnSync } from "node:child_process"; import { readFileSync } from "node:fs"; type JsonRecord = Record; function assertCondition(condition: unknown, message: string, detail: unknown = {}): void { if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`); } function asRecord(value: unknown, label: string): JsonRecord { assertCondition(typeof value === "object" && value !== null && !Array.isArray(value), `${label} must be an object`, { value }); return value as JsonRecord; } function asStringArray(value: unknown, label: string): string[] { assertCondition(Array.isArray(value) && value.every((item) => typeof item === "string"), `${label} must be a string array`, value); return value as string[]; } function runCli(args: string[], expectStatus: number): JsonRecord { const result = spawnSync("bun", ["scripts/cli.ts", ...args], { cwd: process.cwd(), encoding: "utf8", maxBuffer: 8 * 1024 * 1024, }); assertCondition(result.status === expectStatus, `cli status mismatch for ${args.join(" ")}`, { status: result.status, stdout: result.stdout.slice(-3000), stderr: result.stderr.slice(-3000), }); return asRecord(JSON.parse(result.stdout) as unknown, "cli envelope"); } function firstService(envelope: JsonRecord, label: string): JsonRecord { const data = asRecord(envelope.data, `${label} data`); const services = Array.isArray(data.services) ? data.services : []; assertCondition(services.length === 1, `${label} should return exactly one service`, data); return asRecord(services[0], `${label} service`); } function includes(value: unknown, expected: string): boolean { return Array.isArray(value) && value.some((item) => item === expected); } const commit = "0123456789abcdef0123456789abcdef01234567"; const devPlan = firstService(runCli(["deploy", "plan", "--env", "dev", "--service", "code-queue"], 0), "dev plan"); const devArtifact = asRecord(devPlan.artifactConsumer, "dev artifactConsumer"); const devTarget = asRecord(devPlan.target, "dev target"); const devBoundary = asRecord(devPlan.boundary, "dev boundary"); const devCd = asRecord(devBoundary.cdConsumer, "dev cdConsumer"); const devPlanLiveApply = asRecord(devPlan.liveApply, "dev plan liveApply"); const devPlanGuard = asRecord(devBoundary.selfBootstrapGuard, "dev boundary selfBootstrapGuard"); const devArtifactGuard = asRecord(devArtifact.selfBootstrapGuard, "dev artifact selfBootstrapGuard"); const devBuild = asRecord(devArtifact.build, "dev artifact build"); const devRegistry = asRecord(devArtifact.registry, "dev artifact registry"); assertCondition(devArtifact.consumerKind === "d601-k3s-managed", "dev Code Queue must be a k3s-managed artifact consumer", devArtifact); assertCondition(devArtifact.noRuntimeSourceBuild === true, "dev Code Queue must not build source on the runtime target", devArtifact); assertCondition(devArtifact.dryRunOnly === true, "dev Code Queue artifact consumer must be dry-run-only until human authorization", devArtifact); assertCondition(String(devArtifact.blockedReason ?? "").includes("self-bootstrap"), "dev Code Queue blocked reason should name self-bootstrap", devArtifact); assertCondition(devArtifact.requiresSupervisorApproval === true, "dev Code Queue artifact consumer should require supervisor approval", devArtifact); assertCondition(devBuild.willRunDockerBuild === false && devBuild.willRunDockerComposeBuild === false, "dev Code Queue CD must be pull-only/no-build", devBuild); assertCondition(devRegistry.tag === devPlan.commitId && String(devRegistry.imageRef ?? "").endsWith(`:${devPlan.commitId}`), "dev Code Queue registry plan must expose commit tag/image", devRegistry); assertCondition(devTarget.namespace === "unidesk-dev", "dev Code Queue target namespace must be unidesk-dev", devTarget); assertCondition(devTarget.deployment === "code-queue-scheduler-dev", "dev Code Queue should target the dev scheduler deployment", devTarget); assertCondition(devPlanLiveApply.allowed === false, "dev Code Queue live apply must be blocked for Code Queue automation", devPlanLiveApply); assertCondition(devPlanLiveApply.requiresSupervisorApproval === true, "dev Code Queue live apply must require supervisor approval", devPlanLiveApply); assertCondition(devPlanGuard.selfBootstrapBlocked === true && devArtifactGuard.selfBootstrapBlocked === true, "dev Code Queue must expose self-bootstrap guards", { devPlanGuard, devArtifactGuard }); assertCondition(devCd.prodMutationAllowed === false, "dev Code Queue boundary must prohibit production mutation", devCd); assertCondition(devCd.liveApplyAllowed === false, "dev Code Queue boundary must not advertise direct live apply", devCd); assertCondition(devCd.liveApplyCommandShape === null, "dev Code Queue boundary must not advertise a run-now command", devCd); assertCondition(devCd.requiresSupervisorApproval === true, "dev Code Queue boundary should require supervisor approval", devCd); assertCondition(String(devCd.manualAuthorizationPoint ?? "").includes("DEV apply"), "dev Code Queue boundary should expose the DEV manual authorization point", devCd); assertCondition(asRecord(devBoundary.ciProducer, "dev ciProducer").allowed === true, "Code Queue CI producer should be allowed for image publication", devBoundary); assertCondition(includes(devTarget.forbiddenActions, "docker build"), "dev target must forbid runtime docker build", devTarget); assertCondition(includes(devTarget.forbiddenActions, "NodePort"), "dev target must forbid NodePort", devTarget); const prodPlan = firstService(runCli(["deploy", "plan", "--env", "prod", "--service", "code-queue"], 1), "prod plan"); const prodArtifact = asRecord(prodPlan.artifactConsumer, "prod artifactConsumer"); const prodTarget = asRecord(prodPlan.target, "prod target"); const prodBoundary = asRecord(prodPlan.boundary, "prod boundary"); const prodCd = asRecord(prodBoundary.cdConsumer, "prod cdConsumer"); const prodGuard = asRecord(prodBoundary.selfBootstrapGuard, "prod boundary selfBootstrapGuard"); const prodLiveApply = asRecord(prodPlan.liveApply, "prod liveApply"); const prodUnsupported = asRecord(prodPlan.unsupported, "prod unsupported"); const prodForbidden = asStringArray(prodTarget.forbiddenActions, "prod forbiddenActions"); assertCondition(prodPlan.deploymentPath === "unsupported", "prod Code Queue deployment path must be unsupported", prodPlan); assertCondition(prodArtifact.consumerKind === "unsupported", "prod Code Queue artifact consumer must be unsupported", prodArtifact); assertCondition(prodArtifact.registryImage === null, "prod Code Queue plan must not advertise a production registry image target", prodArtifact); assertCondition(prodArtifact.noRuntimeSourceBuild === true, "prod Code Queue plan must still block runtime source builds", prodArtifact); assertCondition(prodArtifact.requiresSupervisorApproval === true, "prod Code Queue artifact consumer should require supervisor approval", prodArtifact); assertCondition(prodTarget.runtimeHost === null, "prod Code Queue plan must not expose a runtime host target", prodTarget); assertCondition(prodTarget.deployCommandShape === "none", "prod Code Queue plan must not expose a deploy command shape", prodTarget); assertCondition(prodLiveApply.allowed === false, "prod Code Queue live apply must be blocked", prodLiveApply); assertCondition(String(prodLiveApply.reason ?? "").includes("production CD is intentionally unsupported"), "prod blocked reason should name the intentional CD gap", prodLiveApply); assertCondition(String(prodUnsupported.reason ?? "").includes("prod artifact deploy"), "prod unsupported reason should mention prod artifact deploy", prodUnsupported); assertCondition(prodCd.prodMutationAllowed === false, "prod Code Queue boundary must prohibit production mutation", prodCd); assertCondition(prodCd.liveApplyCommandShape === null, "prod Code Queue boundary must not advertise a live apply command", prodCd); assertCondition(prodCd.requiresSupervisorApproval === true, "prod Code Queue boundary should require supervisor approval", prodCd); assertCondition(prodGuard.selfBootstrapBlocked === true, "prod Code Queue boundary should expose self-bootstrap guard", prodGuard); assertCondition(String(prodCd.manualAuthorizationPoint ?? "").includes("future supervisor-approved"), "prod boundary should require a future supervisor-approved design", prodCd); assertCondition(prodForbidden.includes("production namespace mutation"), "prod forbidden actions must include production namespace mutation", prodTarget); assertCondition(prodForbidden.includes("interrupt running Code Queue tasks"), "prod forbidden actions must include task interrupt", prodTarget); assertCondition(prodForbidden.includes("cancel running Code Queue tasks"), "prod forbidden actions must include task cancel", prodTarget); assertCondition(JSON.stringify(prodTarget).includes("code-queue-read"), "prod excluded targets should name production Code Queue deployments", prodTarget); const devArtifactDryRun = asRecord(runCli([ "artifact-registry", "deploy-service", "--env", "dev", "--service", "code-queue", "--commit", commit, "--dry-run", ], 0).data, "dev artifact-registry dry-run"); const artifactTarget = asRecord(devArtifactDryRun.target, "artifact dry-run target"); const artifactRegistry = asRecord(devArtifactDryRun.registry, "artifact dry-run registry"); const artifactBuild = asRecord(devArtifactDryRun.build, "artifact dry-run build"); const artifactLiveApply = asRecord(devArtifactDryRun.liveApply, "artifact dry-run liveApply"); const artifactGuard = asRecord(devArtifactDryRun.selfBootstrapGuard, "artifact dry-run selfBootstrapGuard"); const artifactAffectedRuntime = asRecord(devArtifactDryRun.affectedRuntime, "artifact dry-run affectedRuntime"); const artifactExcludedTargets = JSON.stringify(devArtifactDryRun.excludedTargets); assertCondition(devArtifactDryRun.mutation === false, "artifact-registry dev dry-run must be non-mutating", devArtifactDryRun); assertCondition(devArtifactDryRun.requiresSupervisorApproval === true, "artifact-registry dev dry-run must require supervisor approval", devArtifactDryRun); assertCondition(artifactRegistry.imageRef === `127.0.0.1:5000/unidesk/code-queue:${commit}`, "artifact-registry dev dry-run should expose commit-pinned image", artifactRegistry); assertCondition(artifactRegistry.digest === null && String(artifactRegistry.digestSource ?? "").includes("manifest HEAD"), "artifact-registry dev dry-run should expose digest provenance", artifactRegistry); assertCondition(artifactBuild.willCompile === false && artifactBuild.willRunDockerBuild === false && artifactBuild.willRunDockerComposeBuild === false, "artifact-registry dev dry-run must be pull-only/no-build", artifactBuild); assertCondition(artifactLiveApply.allowed === false && artifactLiveApply.policy === "supervisor-only", "artifact-registry dev dry-run must block self-bootstrap live apply", artifactLiveApply); assertCondition(artifactLiveApply.requiresSupervisorApproval === true, "artifact-registry dev liveApply should require supervisor approval", artifactLiveApply); assertCondition(artifactGuard.selfBootstrapBlocked === true, "artifact-registry dev dry-run must expose self-bootstrap guard", artifactGuard); assertCondition(artifactAffectedRuntime.productionNamespaceAffected === false, "artifact-registry dev dry-run must not affect production namespace", artifactAffectedRuntime); assertCondition(artifactAffectedRuntime.activeTaskInterruptCancelAffected === false, "artifact-registry dev dry-run must not affect active task control", artifactAffectedRuntime); assertCondition(artifactExcludedTargets.includes("active tasks") && artifactExcludedTargets.includes("cancel"), "artifact-registry dev dry-run should exclude active task interrupt/cancel", devArtifactDryRun); assertCondition(artifactTarget.namespace === "unidesk-dev", "artifact-registry dev dry-run must target unidesk-dev", artifactTarget); const prodArtifactDryRun = asRecord(runCli([ "artifact-registry", "deploy-service", "--env", "prod", "--service", "code-queue", "--commit", commit, "--dry-run", ], 1).data, "prod artifact-registry dry-run"); assertCondition(prodArtifactDryRun.error === "unsupported-environment", "artifact-registry prod code-queue should be unsupported", prodArtifactDryRun); assertCondition(Array.isArray(prodArtifactDryRun.supportedEnvironments) && prodArtifactDryRun.supportedEnvironments.length === 1 && prodArtifactDryRun.supportedEnvironments[0] === "dev", "artifact-registry prod code-queue should expose only dev as supported", prodArtifactDryRun); assertCondition(prodArtifactDryRun.requiresSupervisorApproval === true, "artifact-registry prod code-queue should require supervisor approval before any future design", prodArtifactDryRun); assertCondition(asRecord(prodArtifactDryRun.selfBootstrapGuard, "prod artifact selfBootstrapGuard").selfBootstrapBlocked === true, "artifact-registry prod code-queue should expose self-bootstrap guard", prodArtifactDryRun); assertCondition(JSON.stringify(prodArtifactDryRun).includes("production artifact deploy") && JSON.stringify(prodArtifactDryRun).includes("active task"), "artifact-registry prod code-queue should explain prod deploy and active-task boundaries", prodArtifactDryRun); const ciSource = readFileSync("scripts/src/ci.ts", "utf8"); assertCondition(ciSource.includes('type CiPublishTransport = "auto" | "tekton" | "direct-docker"'), "ci publish-user-service should expose an explicit transport selector"); assertCondition(ciSource.includes('options.transport === "direct-docker"'), "ci publish-user-service should support direct-docker artifact publish"); assertCondition(ciSource.includes('options.transport === "auto" && options.serviceId === "code-queue"'), "auto transport should select direct-docker for Code Queue artifacts"); assertCondition(ciSource.includes("dependsOnLocalUnideskDatabase: false"), "direct-docker publish must not depend on local unidesk-database dispatch"); assertCondition(ciSource.includes("CODE_QUEUE_BASE_IMAGE=unidesk-code-queue:d601"), "direct-docker Code Queue publish must use the warmed D601 base image"); assertCondition(ciSource.includes("code-queue-base-image-missing"), "direct-docker Code Queue publish should fail fast when the warmed base image is missing"); assertCondition(ciSource.includes("no deploy apply, no rollout, no Code Queue restart, no active task mutation"), "direct-docker publish boundary should forbid runtime mutation"); assertCondition(ciSource.includes("repo-owned Docker artifact publish without backend-core/database dispatch"), "ci help should describe the repo-owned direct-docker delivery path"); process.stdout.write(`${JSON.stringify({ ok: true, checks: [ "deploy plan exposes Code Queue CI producer and dev CD consumer boundary", "dev Code Queue dry-run targets only unidesk-dev and forbids runtime builds/public ports", "prod Code Queue plan is unsupported and exposes no runtime deploy target", "prod Code Queue boundary forbids self-deploy, prod mutation, interrupt and cancel actions", "artifact-registry dev dry-run is non-mutating while prod remains unsupported", "ci publish-user-service exposes direct-docker Code Queue artifact publish without local database dispatch", ], }, null, 2)}\n`);