import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; import { existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { buildHwlabCdRemoteCommandForTest } from "./src/hwlab-cd"; type JsonRecord = Record; function dataOf(payload: JsonRecord): JsonRecord { return payload.data as JsonRecord; } function runCli(args: string[], env: NodeJS.ProcessEnv = {}): JsonRecord { const result = spawnSync("bun", ["scripts/cli.ts", ...args], { cwd: process.cwd(), env: { ...process.env, UNIDESK_HWLAB_CD_TRANSPORT: "local", ...env, }, encoding: "utf8", timeout: 25_000, }); assert.equal(result.stderr, "", `stderr should be empty: ${result.stderr}`); assert.notEqual(result.stdout.trim(), "", "CLI must not produce empty output"); const parsed = JSON.parse(result.stdout) as JsonRecord; if (result.status !== 0) assert.equal(parsed.ok, false, `nonzero CLI should return ok=false: ${result.stdout}`); return parsed; } function writeJson(path: string, value: unknown): void { writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`); } function makeFakeHwlabRepo(): string { const root = join(tmpdir(), `unidesk-hwlab-cd-wrapper-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`); mkdirSync(join(root, "scripts"), { recursive: true }); mkdirSync(join(root, "deploy/k8s/base"), { recursive: true }); mkdirSync(join(root, "reports/dev-gate"), { recursive: true }); writeFileSync(join(root, "scripts/dev-cd-apply.mjs"), [ "const kubeconfigIndex = process.argv.indexOf('--kubeconfig');", "if (process.argv.includes('--apply') || process.argv.includes('--write-report') || process.argv.includes('--confirm-dev')) { throw new Error('mutation flag must not be used in wrapper tests'); }", "process.stdout.write(JSON.stringify({", " ok: true,", " status: 'pass',", " mode: process.argv.includes('--dry-run') ? 'dry-run' : 'status',", " command: 'dev-cd-apply',", " mutationAttempted: false,", " prodTouched: false,", " target: {", " ref: 'origin/main',", " promotionCommit: 'abc1234567890abcdef',", " shortCommitId: 'abc1234',", " promotionSource: 'deploy/deploy.json',", " publishRequired: false,", " headCommitId: 'abc1234567890abcdef',", " headMatchesTarget: true,", " desiredStateCheck: { status: 'pass', summary: { desiredCommitId: 'abc1234', targetConvergence: 'already_promoted' } },", " artifactBoundary: { status: 'pass', desiredState: { deployCommitId: 'abc1234', catalogCommitId: 'abc1234', deployCommitMatches: true, catalogCommitMatches: true } },", " namespace: 'hwlab-dev'", " },", " deployJson: { path: 'deploy/deploy.json', commitId: 'abc1234', matchesTarget: true },", " artifactCatalog: { path: 'deploy/artifact-catalog.dev.json', commitId: 'abc1234', artifactState: 'published', ciPublished: true, registryVerified: true },", " artifactReport: { path: 'reports/dev-gate/dev-artifacts.json', commitId: 'abc1234' },", " lock: { status: 'absent' },", " liveDelta: { status: 'not_run', reason: '--skip-live-verify' },", " kubeconfig: kubeconfigIndex >= 0 ? process.argv[kubeconfigIndex + 1] : null", "}, null, 2));", ].join("\n")); writeJson(join(root, "deploy/deploy.json"), { commitId: "abc1234", environment: "dev", namespace: "hwlab-dev", endpoint: "http://74.48.78.17:16667" }); writeJson(join(root, "deploy/artifact-catalog.dev.json"), { commitId: "abc1234", artifactState: "published", publish: { ciPublished: true, registryVerified: true }, services: [{ id: "hwlab-cloud-api", digest: "sha256:" + "a".repeat(64) }] }); writeJson(join(root, "reports/dev-gate/dev-artifacts.json"), { commitId: "abc1234", artifactPublish: { sourceCommitId: "abc1234", serviceCount: 1, ciPublished: true, registryVerified: true } }); writeFileSync(join(root, "deploy/k8s/base/workloads.yaml"), "apiVersion: v1\nkind: List\nitems: []\n"); spawnSync("git", ["init", "-b", "main"], { cwd: root, encoding: "utf8" }); spawnSync("git", ["config", "user.email", "test@example.invalid"], { cwd: root, encoding: "utf8" }); spawnSync("git", ["config", "user.name", "HWLAB CD Test"], { cwd: root, encoding: "utf8" }); spawnSync("git", ["remote", "add", "origin", "git@github.com:pikasTech/HWLAB.git"], { cwd: root, encoding: "utf8" }); spawnSync("git", ["add", "."], { cwd: root, encoding: "utf8" }); spawnSync("git", ["commit", "-m", "fixture"], { cwd: root, encoding: "utf8" }); spawnSync("git", ["update-ref", "refs/remotes/origin/main", "HEAD"], { cwd: root, encoding: "utf8" }); writeFileSync(join(root, ".git", "FETCH_HEAD"), "fixture\n"); return root; } function makeFakeBin(mode: "native" | "desktop" | "stale-default" | "wrong-node" | "missing-secret" | "second-plane"): string { const bin = join(tmpdir(), `unidesk-hwlab-cd-bin-${process.pid}-${Date.now()}-${mode}-${Math.random().toString(16).slice(2)}`); mkdirSync(bin, { recursive: true }); const deploymentJson = { items: [ { metadata: { name: "hwlab-cloud-api", labels: { "app.kubernetes.io/name": "hwlab-cloud-api", "hwlab.pikastech.local/service-id": "hwlab-cloud-api" }, annotations: { "deployment.kubernetes.io/revision": "7" }, }, spec: { replicas: 1, template: { spec: { containers: [{ name: "hwlab-cloud-api", image: "127.0.0.1:5000/hwlab/hwlab-cloud-api:abc1234", env: [{ name: "HWLAB_COMMIT_ID", value: "abc1234" }] }] } }, }, status: { availableReplicas: 1, updatedReplicas: 1, unavailableReplicas: 0, conditions: [{ type: "Available", status: "True" }, { type: "Progressing", status: "True", reason: "NewReplicaSetAvailable" }] }, }, { metadata: { name: "hwlab-cloud-web", labels: { "app.kubernetes.io/name": "hwlab-cloud-web", "hwlab.pikastech.local/service-id": "hwlab-cloud-web" }, annotations: { "deployment.kubernetes.io/revision": "8" }, }, spec: { replicas: 1, template: { spec: { containers: [{ name: "hwlab-cloud-web", image: "127.0.0.1:5000/hwlab/hwlab-cloud-web:abc1234", env: [{ name: "HWLAB_COMMIT_ID", value: "abc1234" }] }] } }, }, status: { availableReplicas: 1, updatedReplicas: 1, unavailableReplicas: 0, conditions: [{ type: "Available", status: "True" }, { type: "Progressing", status: "True" }] }, }, ], }; const podsJson = { items: [ { metadata: { name: "hwlab-cloud-api-abc" }, status: { containerStatuses: [{ name: "hwlab-cloud-api", image: "127.0.0.1:5000/hwlab/hwlab-cloud-api:abc1234", imageID: "docker-pullable://127.0.0.1:5000/hwlab/hwlab-cloud-api@sha256:" + "b".repeat(64), state: { running: {} } }] }, }, ], }; const jobsJson = { items: [{ metadata: { name: "hwlab-runtime-provision-old" }, status: { succeeded: 1, failed: 0, active: 0, completionTime: "2026-05-24T00:00:00Z" } }] }; const explicitContext = mode === "desktop" ? "docker-desktop" : "default"; const explicitServer = mode === "desktop" ? "https://127.0.0.1:11700" : "https://127.0.0.1:6443"; const explicitNodes = mode === "desktop" ? "desktop-control-plane" : mode === "wrong-node" ? "d602" : "d601"; const defaultContext = mode === "stale-default" ? "docker-desktop" : mode === "second-plane" ? "other-k3s" : explicitContext; const defaultServer = mode === "stale-default" ? "https://127.0.0.1:11700" : mode === "second-plane" ? "https://10.0.0.2:6443" : explicitServer; const defaultNodes = mode === "stale-default" ? "desktop-control-plane" : explicitNodes; const defaultNamespaceOk = mode === "second-plane"; writeFileSync(join(bin, "kubectl"), [ "#!/usr/bin/env bash", "set -euo pipefail", "context=" + JSON.stringify(explicitContext), "server=" + JSON.stringify(explicitServer), "nodes=" + JSON.stringify(explicitNodes), "if [[ \"${KUBECONFIG:-}\" == '' ]]; then", " context=" + JSON.stringify(defaultContext), " server=" + JSON.stringify(defaultServer), " nodes=" + JSON.stringify(defaultNodes), "fi", "if [[ \"$*\" == 'config current-context' ]]; then printf '%s\\n' \"$context\"; exit 0; fi", "if [[ \"$*\" == 'config view --minify -o jsonpath={.clusters[0].cluster.server}' ]]; then printf '%s' \"$server\"; exit 0; fi", "if [[ \"$*\" == 'get nodes -o jsonpath={range .items[*]}{.metadata.name}{\"\\n\"}{end}' ]]; then printf '%s\\n' \"$nodes\"; exit 0; fi", "if [[ \"$*\" == 'get namespace hwlab-dev -o name' ]]; then", " if [[ \"${KUBECONFIG:-}\" == '' && " + JSON.stringify(defaultNamespaceOk ? "yes" : "no") + " == 'yes' ]]; then printf 'namespace/hwlab-dev\\n'; exit 0; fi", " if [[ \"${KUBECONFIG:-}\" != '' ]]; then printf 'namespace/hwlab-dev\\n'; exit 0; fi", " printf 'Error from server (NotFound): namespaces \"hwlab-dev\" not found\\n' >&2; exit 1", "fi", "if [[ \"$*\" =~ ^-n[[:space:]]+hwlab-dev[[:space:]]+get[[:space:]]+lease[[:space:]]+hwlab-dev-cd-lock[[:space:]]+-o[[:space:]]+json$ ]]; then printf 'Error from server (NotFound): leases.coordination.k8s.io \"hwlab-dev-cd-lock\" not found\\n' >&2; exit 1; fi", "if [[ \"$*\" == '-n hwlab-dev get deployments -o json' ]]; then printf '%s\\n' " + JSON.stringify(JSON.stringify(deploymentJson)) + "; exit 0; fi", "if [[ \"$*\" == '-n hwlab-dev get pods -o json' ]]; then printf '%s\\n' " + JSON.stringify(JSON.stringify(podsJson)) + "; exit 0; fi", "if [[ \"$*\" == '-n hwlab-dev get jobs -o json' ]]; then printf '%s\\n' " + JSON.stringify(JSON.stringify(jobsJson)) + "; exit 0; fi", "if [[ \"$*\" == '-n hwlab-dev get secret hwlab-code-agent-provider -o name' && " + JSON.stringify(mode) + " == 'missing-secret' ]]; then printf 'Error from server (NotFound): secrets \"hwlab-code-agent-provider\" not found\\n' >&2; exit 1; fi", "if [[ \"$*\" =~ ^-n\\ hwlab-dev\\ get\\ secret\\ ([^[:space:]]+)\\ -o\\ name$ ]]; then printf 'secret/%s\\n' \"${BASH_REMATCH[1]}\"; exit 0; fi", "if [[ \"$*\" == '-n hwlab-dev describe secret hwlab-cloud-api-dev-db' ]]; then printf 'Name: hwlab-cloud-api-dev-db\\nData\\n====\\ndatabase-url: 48 bytes\\n'; exit 0; fi", "if [[ \"$*\" == '-n hwlab-dev describe secret hwlab-cloud-api-dev-db-admin' ]]; then printf 'Name: hwlab-cloud-api-dev-db-admin\\nData\\n====\\nadmin-url: 48 bytes\\n'; exit 0; fi", "if [[ \"$*\" == '-n hwlab-dev describe secret hwlab-code-agent-provider' ]]; then printf 'Name: hwlab-code-agent-provider\\nData\\n====\\nopenai-api-key: 48 bytes\\n'; exit 0; fi", "printf 'unexpected kubectl args: %s\\n' \"$*\" >&2; exit 99", ].join("\n")); spawnSync("chmod", ["+x", join(bin, "kubectl")]); writeFileSync(join(bin, "curl"), [ "#!/usr/bin/env bash", "set -euo pipefail", "url=\"${@: -1}\"", "if [[ \"$*\" == *'http://127.0.0.1:5000/v2/'* ]]; then printf '{}\\n'; exit 0; fi", "if [[ \"$url\" == 'http://74.48.78.17:16666/health/live' ]]; then printf '%s\\n' " + JSON.stringify(JSON.stringify({ serviceId: "hwlab-cloud-web", environment: "dev", status: "ready", ready: true, commit: { id: "abc1234" }, image: { reference: "127.0.0.1:5000/hwlab/hwlab-cloud-web:abc1234", tag: "abc1234" }, blockerCodes: [], })) + "; exit 0; fi", "if [[ \"$url\" == 'http://74.48.78.17:16667/health/live' ]]; then printf '%s\\n' " + JSON.stringify(JSON.stringify({ serviceId: "hwlab-cloud-api", environment: "dev", status: "ready", ready: true, commit: { id: "abc1234" }, image: { reference: "127.0.0.1:5000/hwlab/hwlab-cloud-api:abc1234", tag: "abc1234" }, db: { ready: true, connected: true, liveDbEvidence: true, runtimeReadiness: { status: "ready", ready: true, blocker: null } }, runtime: { status: "ready", ready: true, durable: true, durableRequested: true, liveRuntimeEvidence: true, blocker: null, adapter: "postgres" }, blockerCodes: [], })) + "; exit 0; fi", "printf 'unexpected curl args: %s\\n' \"$*\" >&2; exit 22", ].join("\n")); spawnSync("chmod", ["+x", join(bin, "curl")]); return bin; } function scopes(data: JsonRecord): string[] { return ((data.blockers ?? []) as JsonRecord[]).map((blocker) => String(blocker.scope ?? "")); } function withLocalTransport(args: string[]): string[] { return [...args, "--transport", "local"]; } const fakeRepo = makeFakeHwlabRepo(); const nativeBin = makeFakeBin("native"); const desktopBin = makeFakeBin("desktop"); const staleDefaultBin = makeFakeBin("stale-default"); const wrongNodeBin = makeFakeBin("wrong-node"); const missingSecretBin = makeFakeBin("missing-secret"); const secondPlaneBin = makeFakeBin("second-plane"); const help = runCli(["hwlab", "help"]); assert.equal(help.ok, true); assert.equal((help.data as JsonRecord).command, "hwlab cd"); assert.equal(((help.data as JsonRecord).usage as string[]).includes("bun scripts/cli.ts hwlab cd audit --env dev"), true); const remoteCommand = buildHwlabCdRemoteCommandForTest(withLocalTransport(["cd", "apply", "--env", "dev", "--dry-run"])); assert.equal(remoteCommand.includes("scripts/dev-cd-apply.mjs"), true); assert.equal(remoteCommand.includes("/etc/rancher/k3s/k3s.yaml"), true); assert.equal(remoteCommand.includes("kubectl rollout"), false); assert.equal(remoteCommand.includes("kubectl apply"), false); assert.equal(remoteCommand.includes("break-stale-lock"), false); const realApply = runCli(["hwlab", "cd", "apply", "--env", "dev", "--hwlab-repo", fakeRepo], { PATH: `${nativeBin}:${process.env.PATH ?? ""}`, }); assert.equal(realApply.ok, false); assert.equal(dataOf(realApply).error, "host-commander-only-real-apply"); assert.equal((dataOf(realApply).safety as JsonRecord).rolloutExecuted, false); const runnerHistoryRepo = runCli(withLocalTransport([ "hwlab", "cd", "status", "--env", "dev", "--hwlab-repo", "/home/ubuntu/hwlab", ]), { PATH: `${nativeBin}:${process.env.PATH ?? ""}`, }); assert.equal(runnerHistoryRepo.ok, false); assert.equal((dataOf(runnerHistoryRepo).repo as JsonRecord).rejected, true); const applyDryRun = runCli(withLocalTransport([ "hwlab", "cd", "apply", "--env", "dev", "--dry-run", "--hwlab-repo", fakeRepo, ]), { PATH: `${nativeBin}:${process.env.PATH ?? ""}`, }); assert.equal(applyDryRun.ok, true); const dryRunData = dataOf(applyDryRun); assert.equal(dryRunData.dryRun, true); assert.equal(dryRunData.mutation, false); assert.equal((dryRunData.safety as JsonRecord).kubectlApplyExecuted, false); assert.equal((dryRunData.safety as JsonRecord).rolloutExecuted, false); assert.equal((dryRunData.safety as JsonRecord).liveVerifyExecuted, false); assert.equal((dryRunData.safety as JsonRecord).cdLockMutated, false); assert.equal((dryRunData.safety as JsonRecord).secretValuesPrinted, false); assert.equal((dryRunData.remote as JsonRecord).providerId, "D601"); assert.equal(((dryRunData.remote as JsonRecord).commandCalls as unknown[]).includes("scripts/dev-cd-apply.mjs"), true); assert.equal((dryRunData.kubeconfig as JsonRecord).path, "/etc/rancher/k3s/k3s.yaml"); assert.equal((dryRunData.nodeGuard as JsonRecord).requiredNodePresent, true); assert.equal((dryRunData.worktreeGuard as JsonRecord).clean, true); assert.equal((dryRunData.secretPreflight as JsonRecord).status, "pass"); assert.equal((dryRunData.controlledDevCd as JsonRecord).controlledEntrypoint, "scripts/dev-cd-apply.mjs"); assert.equal(((dryRunData.target as JsonRecord).promotionCommit), "abc1234567890abcdef"); assert.equal(((dryRunData.promotion as JsonRecord).source), "deploy/deploy.json"); assert.equal(JSON.stringify(dryRunData).includes("sk-secret"), false); const reportsBefore = existsSync(join(fakeRepo, "reports")) ? JSON.stringify(readdirSync(join(fakeRepo, "reports"), { recursive: true })) : ""; const audit = runCli(withLocalTransport([ "hwlab", "cd", "audit", "--env", "dev", "--hwlab-repo", fakeRepo, ]), { PATH: `${nativeBin}:${process.env.PATH ?? ""}`, }); assert.equal(audit.ok, true); const auditData = dataOf(audit); const auditSummary = auditData.audit as JsonRecord; assert.equal(auditSummary.status, "pass"); assert.equal((auditSummary.namespace), "hwlab-dev"); assert.equal(((auditSummary.nodeGuard as JsonRecord).nodeNames as unknown[]).includes("d601"), true); assert.equal(((auditSummary.secrets as JsonRecord).valuesRead), false); assert.equal(((auditSummary.secrets as JsonRecord).valuesPrinted), false); assert.equal(JSON.stringify(auditSummary).includes("48 bytes"), false); assert.equal(((auditSummary.registry as JsonRecord).status), "pass"); assert.equal(((auditSummary.lease as JsonRecord).staleClassification), "not-held"); assert.equal((((auditSummary.desiredState as JsonRecord).imageConvergence as JsonRecord).status), "pass"); assert.equal(((auditSummary.workload as JsonRecord).status), "healthy"); assert.equal(((auditSummary.publicHealth as JsonRecord).status), "pass"); assert.equal(((auditSummary.durability as JsonRecord).status), "pass"); assert.deepEqual((auditSummary.blockerTypes as unknown[]), []); assert.equal(((auditSummary.safety as JsonRecord).reportsWritten), false); assert.equal(((auditSummary.safety as JsonRecord).cdLockMutated), false); assert.equal((auditData.remote as JsonRecord).providerId, "D601"); assert.equal(JSON.stringify(auditData).length < 80_000, true); assert.equal(JSON.stringify(auditData).includes("kubectl apply"), false); assert.equal(JSON.stringify(auditData).includes("kubectl rollout"), false); assert.equal(JSON.stringify(auditData).includes("--apply"), false); assert.equal(JSON.stringify(auditData).includes("--write-report"), false); assert.equal(JSON.stringify(auditData).includes("sk-secret"), false); const reportsAfter = existsSync(join(fakeRepo, "reports")) ? JSON.stringify(readdirSync(join(fakeRepo, "reports"), { recursive: true })) : ""; assert.equal(reportsAfter, reportsBefore); const status = runCli(withLocalTransport([ "hwlab", "cd", "status", "--env", "dev", "--hwlab-repo", fakeRepo, ]), { PATH: `${nativeBin}:${process.env.PATH ?? ""}`, }); assert.equal(status.ok, true); const statusData = dataOf(status); assert.equal((statusData.secretPreflight as JsonRecord).status, "skipped"); assert.equal((statusData.lockState as JsonRecord).status, "absent"); assert.ok(typeof statusData.reportDumpPath === "string"); const staleDefaultOk = runCli(withLocalTransport([ "hwlab", "cd", "apply", "--env", "dev", "--dry-run", "--hwlab-repo", fakeRepo, ]), { PATH: `${staleDefaultBin}:${process.env.PATH ?? ""}`, KUBECONFIG: "", }); assert.equal(staleDefaultOk.ok, true); const staleDefaultGuard = dataOf(staleDefaultOk).nodeGuard as JsonRecord; assert.equal(staleDefaultGuard.status, "pass"); assert.equal(staleDefaultGuard.refusal, false); assert.equal((staleDefaultGuard.defaultKubectlDiagnostic as JsonRecord).status, "stale-forbidden-default"); const desktopRefusal = runCli(withLocalTransport([ "hwlab", "cd", "audit", "--env", "dev", "--hwlab-repo", fakeRepo, ]), { PATH: `${desktopBin}:${process.env.PATH ?? ""}`, }); assert.equal(desktopRefusal.ok, false); const desktopData = dataOf(desktopRefusal); assert.equal(desktopData.status, "refused"); assert.deepEqual((((desktopData.audit as JsonRecord).nodeGuard as JsonRecord).refusalSignals), ["docker-desktop", "desktop-control-plane", "127.0.0.1:11700"]); assert.equal(((desktopData.blockerTypes as unknown[]).includes("docker-desktop-context-risk")), true); const wrongNodeBlocked = runCli(withLocalTransport([ "hwlab", "cd", "apply", "--env", "dev", "--dry-run", "--hwlab-repo", fakeRepo, ]), { PATH: `${wrongNodeBin}:${process.env.PATH ?? ""}`, }); assert.equal(wrongNodeBlocked.ok, false); const wrongNodeData = dataOf(wrongNodeBlocked); assert.equal((wrongNodeData.nodeGuard as JsonRecord).requiredNodePresent, false); assert.equal(scopes(wrongNodeData).includes("d601-native-k3s-guard"), true); const missingSecretBlocked = runCli(withLocalTransport([ "hwlab", "cd", "apply", "--env", "dev", "--dry-run", "--hwlab-repo", fakeRepo, ]), { PATH: `${missingSecretBin}:${process.env.PATH ?? ""}`, }); assert.equal(missingSecretBlocked.ok, false); const missingSecretData = dataOf(missingSecretBlocked); assert.equal((missingSecretData.secretPreflight as JsonRecord).status, "blocked"); assert.equal((missingSecretData.controlledDevCd as JsonRecord).status, "skipped"); assert.equal(scopes(missingSecretData).includes("secretref:hwlab-code-agent-provider/openai-api-key"), true); assert.equal(JSON.stringify(missingSecretData).includes("sk-secret"), false); const secondPlaneBlocked = runCli(withLocalTransport([ "hwlab", "cd", "apply", "--env", "dev", "--dry-run", "--hwlab-repo", fakeRepo, ]), { PATH: `${secondPlaneBin}:${process.env.PATH ?? ""}`, }); assert.equal(secondPlaneBlocked.ok, false); assert.equal(((dataOf(secondPlaneBlocked).nodeGuard as JsonRecord).defaultKubectlDiagnostic as JsonRecord).secondControlPlaneRisk, true); assert.equal(scopes(dataOf(secondPlaneBlocked)).includes("second-hwlab-dev-control-plane"), true); writeFileSync(join(fakeRepo, "dirty.txt"), "dirty\n"); const dirtyBlocked = runCli(withLocalTransport([ "hwlab", "cd", "apply", "--env", "dev", "--dry-run", "--hwlab-repo", fakeRepo, ]), { PATH: `${nativeBin}:${process.env.PATH ?? ""}`, }); assert.equal(dirtyBlocked.ok, false); assert.equal(scopes(dataOf(dirtyBlocked)).includes("hwlab-git-clean"), true); console.log(JSON.stringify({ ok: true, checked: "hwlab-cd-wrapper-contract" }));