test: guard code queue artifact dry-run readiness

This commit is contained in:
Codex
2026-05-21 14:31:00 +00:00
parent 9a4624a6b1
commit 7e171dd904
10 changed files with 291 additions and 31 deletions
+150 -13
View File
@@ -140,6 +140,8 @@ interface ArtifactConsumerSpec {
targets: Partial<Record<ArtifactDeployEnvironment, ArtifactConsumerTarget>>;
prodLiveApply: "enabled" | "supervisor-only" | "unsupported";
prodLiveBlockReason?: string;
devLiveApply?: "enabled" | "supervisor-only";
devLiveBlockReason?: string;
runtimeVerification?: "strict" | "blocked";
runtimeVerificationBlockReason?: string;
}
@@ -503,7 +505,9 @@ const artifactConsumerSpecs: Record<string, ArtifactConsumerSpec> = {
registryRepository: "unidesk/code-queue",
dockerfile: "src/components/microservices/code-queue/Dockerfile",
prodLiveApply: "unsupported",
prodLiveBlockReason: "code-queue is dev-only for artifact consumer validation and has no prod artifact deploy, rollout, or manifest mutation target.",
prodLiveBlockReason: "code-queue is dev-only for artifact consumer validation and has no production artifact deploy, production rollout, or production manifest mutation target.",
devLiveApply: "supervisor-only",
devLiveBlockReason: "Code Queue DEV live apply is self-bootstrap sensitive: a running Code Queue task may plan only dry-run evidence. A human operator or supervisor must explicitly authorize DEV apply outside Code Queue after reviewing the CI artifact digest and dry-run target list.",
targets: {
dev: {
targetImage: "unidesk-code-queue:dev",
@@ -1315,6 +1319,10 @@ function unsupportedService(serviceId: string, options: ArtifactRegistryOptions)
function unsupportedEnvironment(spec: ArtifactConsumerSpec, options: ArtifactRegistryOptions): Record<string, unknown> {
const environment = options.environment ?? "prod";
const codeQueueGuard = spec.serviceId === "code-queue" ? codeQueueSelfBootstrapGuard(environment) : undefined;
const reason = spec.serviceId === "code-queue" && environment === "prod"
? spec.prodLiveBlockReason ?? "Code Queue production artifact deploy, rollout and manifest mutation are intentionally unsupported in this phase."
: `No standardized ${environment} registry artifact consumer is implemented for ${spec.serviceId}.`;
return {
ok: false,
supported: false,
@@ -1322,14 +1330,125 @@ function unsupportedEnvironment(spec: ArtifactConsumerSpec, options: ArtifactReg
serviceId: spec.serviceId,
environment,
providerId: options.providerId,
reason: `No standardized ${environment} registry artifact consumer is implemented for ${spec.serviceId}.`,
reason,
supportedEnvironments: Object.keys(spec.targets),
requiresSupervisorApproval: spec.serviceId === "code-queue",
selfBootstrapGuard: codeQueueGuard,
affectedRuntime: spec.serviceId === "code-queue" ? codeQueueAffectedRuntime(environment, false) : undefined,
excludedTargets: spec.serviceId === "code-queue" ? codeQueueExcludedTargets(environment) : undefined,
policy: "artifact CD must not silently fall back to maintenance-channel source builds or legacy direct deployment",
};
}
function artifactConsumerLivePolicy(spec: ArtifactConsumerSpec, environment: ArtifactDeployEnvironment): "enabled" | "supervisor-only" | "unsupported" {
return environment === "prod" ? spec.prodLiveApply : spec.devLiveApply ?? "enabled";
}
function artifactConsumerLiveBlockReason(spec: ArtifactConsumerSpec, environment: ArtifactDeployEnvironment): string | null {
if (spec.runtimeVerificationBlockReason !== undefined) return spec.runtimeVerificationBlockReason;
return environment === "prod" ? spec.prodLiveBlockReason ?? null : spec.devLiveBlockReason ?? null;
}
function codeQueueExcludedTargets(environment: ArtifactDeployEnvironment): Record<string, unknown>[] {
const excluded: Record<string, unknown>[] = [
{
namespace: "unidesk",
deployments: ["code-queue", "code-queue-read", "code-queue-write", "d601-provider-egress-proxy", "d601-tcp-egress-gateway"],
reason: "production Code Queue execution-plane Deployments are outside this artifact consumer and must not be mutated by dry-run or self-bootstrap automation.",
},
{
operations: ["restart scheduler", "restart runner", "interrupt active tasks", "cancel active tasks"],
reason: "artifact CD planning must not alter scheduler/runner lifecycle or active task control state.",
},
];
if (environment === "dev") {
excluded.push({
namespace: "unidesk-dev",
nonDryRunMutation: "requires explicit supervisor or human authorization outside the running Code Queue task",
reason: "DEV is the only Code Queue artifact consumer target, but self-bootstrap automation may produce dry-run evidence only.",
});
}
return excluded;
}
function codeQueueAffectedRuntime(environment: ArtifactDeployEnvironment, targetPlanned: boolean): Record<string, unknown> {
return {
dryRunMutation: false,
plannedTarget: targetPlanned && environment === "dev"
? {
namespace: "unidesk-dev",
deployments: ["code-queue-scheduler-dev", "code-queue-read-dev", "code-queue-write-dev", "d601-dev-provider-egress-proxy"],
}
: null,
productionNamespaceAffected: false,
productionSchedulerRunnerAffected: false,
activeTaskControlAffected: false,
activeTaskInterruptCancelAffected: false,
};
}
function codeQueueSelfBootstrapGuard(environment: ArtifactDeployEnvironment): Record<string, unknown> {
return {
check: "code-queue-self-bootstrap-guard",
serviceId: "code-queue",
selfBootstrapBlocked: true,
requiresSupervisorApproval: true,
actorBoundary: "a running Code Queue task may publish contract evidence and dry-run plans only; it must not deploy Code Queue itself",
devApply: "requires explicit supervisor or human authorization outside the running Code Queue task",
prodApply: "unsupported until a separate supervisor-approved production Code Queue CD design exists",
allowedWithoutApproval: [
"CI artifact publication",
"deploy plan",
"deploy apply --dry-run",
"artifact-registry deploy-service --dry-run",
],
forbiddenActions: [
"self-deploy Code Queue from Code Queue",
"run a non-dry-run DEV apply from Code Queue",
"production namespace mutation",
"production manifest mutation",
"scheduler or runner restart",
"active task interrupt",
"active task cancel",
],
environment,
};
}
function codeQueueMgrSelfBootstrapGuard(environment: ArtifactDeployEnvironment, requiresSupervisorApproval: boolean): Record<string, unknown> {
return {
check: "code-queue-mgr-control-plane-guard",
serviceId: "code-queue-mgr",
selfBootstrapBlocked: true,
requiresSupervisorApproval,
actorBoundary: "dry-run is allowed, but a running Code Queue task must not replace the Code Queue control-plane sidecar as part of delivering Code Queue itself",
targetScope: "main-server Compose service code-queue-mgr / container code-queue-mgr-backend only",
prodApply: "requires explicit supervisor confirmation",
environment,
forbiddenActions: [
"mutate D601 Code Queue scheduler",
"mutate D601 Code Queue runner",
"restart active tasks",
"interrupt active tasks",
"cancel active tasks",
],
};
}
function artifactConsumerSelfBootstrapGuard(
spec: ArtifactConsumerSpec,
environment: ArtifactDeployEnvironment,
requiresSupervisorApproval: boolean,
): Record<string, unknown> | undefined {
if (spec.serviceId === "code-queue") return codeQueueSelfBootstrapGuard(environment);
if (spec.serviceId === "code-queue-mgr") return codeQueueMgrSelfBootstrapGuard(environment, requiresSupervisorApproval);
return undefined;
}
function artifactConsumerLiveBlock(spec: ArtifactConsumerSpec, options: ArtifactRegistryOptions): Record<string, unknown> | null {
const environment = options.environment ?? "prod";
const livePolicy = artifactConsumerLivePolicy(spec, environment);
const liveReason = artifactConsumerLiveBlockReason(spec, environment);
if (spec.runtimeVerification === "blocked") {
return {
ok: false,
@@ -1347,8 +1466,8 @@ function artifactConsumerLiveBlock(spec: ArtifactConsumerSpec, options: Artifact
policy: "artifact CD must not accept a healthy old service or silently fall back to legacy rebuild paths",
};
}
if (environment !== "prod" || spec.prodLiveApply === "enabled") return null;
if (spec.prodLiveApply === "supervisor-only") {
if (livePolicy === "enabled") return null;
if (livePolicy === "supervisor-only") {
return {
ok: false,
supported: true,
@@ -1357,9 +1476,13 @@ function artifactConsumerLiveBlock(spec: ArtifactConsumerSpec, options: Artifact
serviceId: spec.serviceId,
environment,
providerId: options.providerId,
reason: spec.prodLiveBlockReason ?? `${spec.serviceId} production artifact apply requires supervisor confirmation.`,
dryRunCommandShape: `bun scripts/cli.ts artifact-registry deploy-service --env prod --service ${spec.serviceId} --commit <full-sha> --dry-run`,
policy: "worker automation must not perform live production apply for this infrastructure control-plane service",
reason: liveReason ?? `${spec.serviceId} ${environment} artifact apply requires supervisor confirmation.`,
requiresSupervisorApproval: true,
selfBootstrapGuard: artifactConsumerSelfBootstrapGuard(spec, environment, true),
affectedRuntime: spec.serviceId === "code-queue" ? codeQueueAffectedRuntime(environment, true) : undefined,
excludedTargets: spec.serviceId === "code-queue" ? codeQueueExcludedTargets(environment) : undefined,
dryRunCommandShape: `bun scripts/cli.ts artifact-registry deploy-service --env ${environment} --service ${spec.serviceId} --commit <full-sha> --dry-run`,
policy: "worker automation must not perform live apply for this supervisor-gated artifact consumer",
};
}
return {
@@ -1370,7 +1493,11 @@ function artifactConsumerLiveBlock(spec: ArtifactConsumerSpec, options: Artifact
serviceId: spec.serviceId,
environment,
providerId: options.providerId,
reason: spec.prodLiveBlockReason ?? `${spec.serviceId} does not yet satisfy the artifact consumer runtime verification contract.`,
reason: liveReason ?? `${spec.serviceId} does not yet satisfy the artifact consumer runtime verification contract.`,
requiresSupervisorApproval: spec.serviceId === "code-queue",
selfBootstrapGuard: spec.serviceId === "code-queue" ? codeQueueSelfBootstrapGuard(environment) : undefined,
affectedRuntime: spec.serviceId === "code-queue" ? codeQueueAffectedRuntime(environment, false) : undefined,
excludedTargets: spec.serviceId === "code-queue" ? codeQueueExcludedTargets(environment) : undefined,
requiredBeforeLiveApply: [
"CI can publish a commit-pinned image with matching service id, source repo, source commit, and Dockerfile labels",
"runtime Compose env injects deploy commit/requestedCommit metadata",
@@ -1380,6 +1507,7 @@ function artifactConsumerLiveBlock(spec: ArtifactConsumerSpec, options: Artifact
};
}
function artifactImageRef(options: ArtifactRegistryOptions, spec: ArtifactConsumerSpec, commit: string): string {
return `127.0.0.1:${options.port}/${(options.dryRun ? options.deployJsonService?.artifact?.repository : undefined) ?? spec.registryRepository}:${commit}`;
}
@@ -2627,7 +2755,9 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
: [];
if (drifts.length > 0) return deployJsonDriftResult(deployJsonService, environment, drifts);
const verificationBlocked = spec.runtimeVerification === "blocked";
const livePolicy = environment === "prod" ? spec.prodLiveApply : "enabled";
const livePolicy = artifactConsumerLivePolicy(spec, environment);
const liveReason = artifactConsumerLiveBlockReason(spec, environment);
const requiresSupervisorApproval = livePolicy === "supervisor-only" || spec.serviceId === "code-queue";
const sourceImage = artifactImageRef(effectiveOptions, spec, commit);
const registryEndpoint = `http://127.0.0.1:${effectiveOptions.port}`;
const config = readConfig();
@@ -2689,9 +2819,13 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
boundary: `${environment} CD is artifact-consumer only: verify commit-pinned registry image, pull/import, deploy, then verify live commit/image/health; it never builds source on the runtime target`,
liveApply: {
policy: livePolicy,
allowed: !verificationBlocked && (environment !== "prod" || spec.prodLiveApply === "enabled"),
reason: spec.runtimeVerificationBlockReason ?? (environment === "prod" ? spec.prodLiveBlockReason ?? null : null),
allowed: !verificationBlocked && livePolicy === "enabled",
requiresSupervisorApproval,
reason: liveReason,
},
requiresSupervisorApproval,
selfBootstrapGuard: artifactConsumerSelfBootstrapGuard(spec, environment, requiresSupervisorApproval),
affectedRuntime: spec.serviceId === "code-queue" ? codeQueueAffectedRuntime(environment, true) : undefined,
sourceOfTruth: deployJsonService !== null && hasDeployJsonExecutorContract(deployJsonService) ? deployJsonSourceOfTruth(deployJsonService, environment) : undefined,
driftCheck: deployJsonService !== null && hasDeployJsonExecutorContract(deployJsonService) ? {
ok: true,
@@ -2727,6 +2861,8 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
reason: "dry-run does not mutate D601 Code Queue scheduler, runner, tasks, interrupts, or cancellations.",
},
]
: spec.serviceId === "code-queue"
? codeQueueExcludedTargets(environment)
: undefined,
validation: [
"D601 registry /v2 manifest exists for the commit tag",
@@ -2800,6 +2936,7 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
memory: contractRuntime.memory,
health: contractRuntime.health,
},
excludedTargets: spec.serviceId === "code-queue" ? codeQueueExcludedTargets(environment) : undefined,
validation: [
"D601 registry /v2 manifest exists for the commit tag before mutation",
"D601 Docker-pulled image labels match service id, source repo, source commit, and Dockerfile",
@@ -3183,7 +3320,7 @@ function localHelp(): Record<string, unknown> {
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service mdtodo --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service code-queue --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service code-queue --commit <full-sha> --dry-run [--provider-id D601]",
],
firstStage: "install now writes the rendered systemd/Compose/config files and starts the registry",
artifactConsumers: {
@@ -3218,7 +3355,7 @@ function localHelp(): Record<string, unknown> {
"bun scripts/cli.ts deploy apply --env dev --service met-nonlinear --dry-run",
"bun scripts/cli.ts deploy apply --env dev --service mdtodo",
"bun scripts/cli.ts deploy apply --env dev --service claudeqq",
"bun scripts/cli.ts deploy apply --env dev --service code-queue",
"bun scripts/cli.ts deploy apply --env dev --service code-queue --dry-run",
],
devOnlyConsumers: ["code-queue"],
rollbackShape: "rerun the same artifact consumer with a previous commit-pinned image",