feat: harden HWLAB dev CD wrapper

This commit is contained in:
Codex
2026-05-23 19:21:40 +00:00
parent 7b6f2e55ff
commit 44d8e7e0e7
5 changed files with 475 additions and 95 deletions
+106 -3
View File
@@ -25,7 +25,35 @@ function runCli(args: string[], env: NodeJS.ProcessEnv = {}): JsonRecord {
function makeFakeHwlabRepo(): string {
const root = join(tmpdir(), `unidesk-hwlab-cd-wrapper-${process.pid}-${Date.now()}`);
mkdirSync(join(root, "scripts"), { recursive: true });
writeFileSync(join(root, "scripts/dev-cd-apply.mjs"), "process.stdout.write(JSON.stringify({ok:true}))\n");
writeFileSync(join(root, "scripts/dev-cd-apply.mjs"), [
"const kubeconfigIndex = process.argv.indexOf('--kubeconfig');",
"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-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: 'unknown' },",
" kubeconfig: kubeconfigIndex >= 0 ? process.argv[kubeconfigIndex + 1] : null",
"}, null, 2));",
].join("\n"));
writeFileSync(join(root, "scripts/dev-deploy-apply.mjs"), [
"const dryRun = process.argv.includes('--dry-run');",
"const kubeconfigIndex = process.argv.indexOf('--kubeconfig');",
@@ -49,14 +77,25 @@ function makeFakeHwlabRepo(): string {
writeFileSync(join(root, "scripts/deploy-desired-state-plan.mjs"), [
"process.stdout.write(JSON.stringify({",
" kind: 'hwlab-deploy-desired-state-plan',",
" mode: 'read-only-plan',",
" status: 'pass',",
" source: { deploy: 'deploy/deploy.json', artifactCatalog: 'deploy/artifact-catalog.dev.json', workloads: 'deploy/k8s/base/workloads.yaml', optionalReport: 'reports/dev-gate/dev-artifacts.json' },",
" promotionBoundary: { authoritativeDesiredState: ['deploy/deploy.json', 'deploy/artifact-catalog.dev.json', 'deploy/k8s/base/workloads.yaml'], nonAuthoritativeEvidence: ['reports/dev-gate/dev-artifacts.json'] },",
" summary: { desiredCommitId: 'abc1234', desiredImageTag: 'abc1234', artifactState: 'published', ciPublished: true, registryVerified: true, services: 13, workloadContainers: 13, diagnostics: 0, blockers: 0, targetConvergence: 'not_requested' }",
"}, null, 2));",
].join("\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"): string {
function makeFakeBin(mode: "native" | "desktop" | "stale-default" | "wrong-node" | "missing-secret"): string {
const bin = join(tmpdir(), `unidesk-hwlab-cd-bin-${process.pid}-${Date.now()}-${mode}`);
mkdirSync(bin, { recursive: true });
const explicitContext = mode === "desktop" ? "docker-desktop" : "default";
@@ -81,6 +120,12 @@ function makeFakeBin(mode: "native" | "desktop" | "stale-default" | "wrong-node"
"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 [[ \"$*\" == '-n hwlab-dev get lease hwlab-dev-cd-lock -o 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 deploy -o jsonpath={range .items[*]}{.metadata.name}{\"\\t\"}{range .spec.template.spec.containers[*]}{.name}{\"=\"}{.image}{\",\"}{end}{\"\\n\"}{end}' ]]; then printf 'hwlab-cloud-api\\thwlab-cloud-api=127.0.0.1:5000/hwlab/hwlab-cloud-api:abc1234,\\n'; 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 '{}\\n'",
].join("\n"));
spawnSync("chmod", ["+x", join(bin, "kubectl")]);
@@ -92,6 +137,7 @@ const nativeBin = makeFakeBin("native");
const desktopBin = makeFakeBin("desktop");
const staleDefaultBin = makeFakeBin("stale-default");
const wrongNodeBin = makeFakeBin("wrong-node");
const missingSecretBin = makeFakeBin("missing-secret");
const liveBody = "data:application/json,%7B%22serviceId%22%3A%22hwlab-cloud-web%22%2C%22environment%22%3A%22dev%22%2C%22status%22%3A%22ok%22%2C%22revision%22%3A%22abc1234%22%7D";
const apiBody = "data:application/json,%7B%22serviceId%22%3A%22hwlab-cloud-api%22%2C%22environment%22%3A%22dev%22%2C%22status%22%3A%22ok%22%2C%22revision%22%3A%22abc1234%22%7D";
@@ -99,6 +145,22 @@ const help = runCli(["hwlab", "help"]);
assert.equal(help.ok, true);
assert.equal((help.data as JsonRecord).command, "hwlab cd");
const runnerHistoryRepo = runCli([
"hwlab",
"cd",
"status",
"--env",
"dev",
"--hwlab-repo",
"/home/ubuntu/hwlab",
], {
PATH: `${nativeBin}:${process.env.PATH ?? ""}`,
});
assert.equal(runnerHistoryRepo.ok, false);
const runnerHistoryCandidates = ((runnerHistoryRepo.data as JsonRecord).repo as JsonRecord).candidates as JsonRecord[];
assert.equal(runnerHistoryCandidates[0]?.rejected, true);
assert.equal(runnerHistoryCandidates[0]?.rejectionReason, "runner-history-directory-is-not-hwlab-cd-release-truth");
const applyDryRun = runCli([
"hwlab",
"cd",
@@ -118,7 +180,29 @@ assert.equal(dryRunData.mutation, false);
assert.equal(((dryRunData.d601NativeK3sGuard as JsonRecord).injectedEnv as JsonRecord).KUBECONFIG, "/etc/rancher/k3s/k3s.yaml");
assert.equal((dryRunData.d601NativeK3sGuard as JsonRecord).requiredNodePresent, true);
assert.equal((dryRunData.controlledDryRun as JsonRecord).commandOk, true);
assert.equal((dryRunData.secretRefPreflight as JsonRecord).status, "pass");
assert.equal(((dryRunData.controlledDryRun as JsonRecord).controlledEntrypoint), "scripts/dev-cd-apply.mjs");
assert.equal(((dryRunData.hostCommanderOnlyLiveApply as JsonRecord).commandShape as unknown[]).includes("scripts/dev-cd-apply.mjs"), true);
assert.equal(JSON.stringify(dryRunData).includes("sk-secret"), false);
const preflight = runCli([
"hwlab",
"cd",
"preflight",
"--env",
"dev",
"--hwlab-repo",
fakeRepo,
], {
PATH: `${nativeBin}:${process.env.PATH ?? ""}`,
UNIDESK_HWLAB_CD_TEST_FRONTEND_LIVE_URL: liveBody,
UNIDESK_HWLAB_CD_TEST_API_LIVE_URL: apiBody,
});
assert.equal(preflight.ok, true);
const preflightData = preflight.data as JsonRecord;
assert.equal(preflightData.mutation, false);
assert.equal((preflightData.secretRefPreflight as JsonRecord).status, "pass");
assert.equal((preflightData.liveWorkloads as JsonRecord).status, "observed");
const realApply = runCli([
"hwlab",
@@ -201,10 +285,29 @@ const wrongNodeBlocked = runCli([
], {
PATH: `${wrongNodeBin}:${process.env.PATH ?? ""}`,
});
assert.equal(wrongNodeBlocked.ok, true);
assert.equal(wrongNodeBlocked.ok, false);
const wrongNodeGuard = (wrongNodeBlocked.data as JsonRecord).d601NativeK3sGuard as JsonRecord;
assert.equal(wrongNodeGuard.status, "blocked");
assert.equal(wrongNodeGuard.requiredNodePresent, false);
assert.equal(((wrongNodeBlocked.data as JsonRecord).blockers as JsonRecord[]).some((blocker) => blocker.scope === "d601-native-k3s-guard"), true);
const missingSecretBlocked = runCli([
"hwlab",
"cd",
"apply",
"--env",
"dev",
"--dry-run",
"--hwlab-repo",
fakeRepo,
], {
PATH: `${missingSecretBin}:${process.env.PATH ?? ""}`,
});
assert.equal(missingSecretBlocked.ok, false);
const missingSecretData = missingSecretBlocked.data as JsonRecord;
assert.equal((missingSecretData.secretRefPreflight as JsonRecord).status, "blocked");
assert.equal((missingSecretData.controlledDryRun as JsonRecord).status, "skipped");
assert.equal((missingSecretData.blockers as JsonRecord[]).some((blocker) => blocker.scope === "secretref:hwlab-code-agent-provider/openai-api-key"), true);
assert.equal(JSON.stringify(missingSecretData).includes("sk-secret"), false);
console.log(JSON.stringify({ ok: true, checked: "hwlab-cd-wrapper-contract" }));