import { spawnSync } from "node:child_process"; import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { delimiter, dirname, join, resolve } from "node:path"; import { describe, expect, it } from "vitest"; const root = process.cwd(); const bash = process.platform === "win32" ? ((process.env.PATH ?? "") .split(delimiter) .flatMap((dir) => [ join(dir, "bash.exe"), join(dirname(dir), "bin", "bash.exe"), join(dirname(dirname(dir)), "bin", "bash.exe"), ]) .find((path) => existsSync(path)) ?? "bash") : "bash"; const sha = "a".repeat(40); function simulate(scenario: string, namespace = "", expectedStatus = 0) { const dir = mkdtempSync(join(tmpdir(), "cms-publish-test-")); try { const result = spawnSync( bash, [resolve(root, "scripts/publish-container.sh")], { cwd: dir, encoding: "utf8", timeout: 10000, env: { ...process.env, BASH_ENV: resolve(root, "src/test/publish-container-harness.sh"), TEST_DIR: dir.replaceAll("\\", "/"), TEST_SHA: sha, SCENARIO: scenario, REGISTRY_SERVER: "https://registry.invalid", REGISTRY_REPOSITORY: "owner/cms", REGISTRY_USER: "Simo", REGISTRY_NAMESPACE: namespace, REGISTRY_TOKEN: "fixture-only", }, }, ); if (result.error) throw result.error; expect(result.status, result.stdout + result.stderr).toBe(expectedStatus); return readFileSync(join(dir, "calls"), "utf8"); } finally { rmSync(dir, { recursive: true, force: true }); } } describe("verified application image reuse", () => { it("reuses only the exact image digest that passed deployment checks", () => { const calls = simulate("verified"); expect(calls).toContain( `docker tag sha256:candidate registry.invalid/simo/cms:${sha}`, ); expect(calls).not.toContain("docker build --network=host --build-arg"); expect( calls.indexOf("verify scripts/verify-portable-image.mjs"), ).toBeLessThan(calls.indexOf("regctl image copy")); }); it.each(["missing", "mismatch"])( "builds committed source when verification marker is %s", (scenario) => { const calls = simulate(scenario); expect(calls).toContain("docker build --network=host --build-arg"); expect(calls).not.toContain("docker tag sha256:candidate"); }, ); }); it("uses the token account namespace instead of the repository owner", () => { const calls = simulate("verified"); expect(calls).toContain(`registry.invalid/simo/cms:${sha}\n`); expect(calls).not.toContain("registry.invalid/owner/cms"); }); it("supports an explicit organization namespace", () => { const calls = simulate("verified", "My-Org"); expect(calls).toContain(`registry.invalid/my-org/cms:${sha}\n`); }); it("bounds uploads and verifies both published image configs", () => { const calls = simulate("verified"); expect(calls).toContain("--blob-chunk 8388608 --blob-max 8388608"); expect(calls).not.toContain("docker push"); expect(calls.match(/regctl image import/g)).toHaveLength(2); expect(calls.match(/regctl image copy/g)).toHaveLength(2); expect(calls.match(/regctl manifest get/g)).toHaveLength(4); expect(calls.match(/--platform linux\/amd64/g)).toHaveLength(4); }); it.each(["upload-fails", "wrong-config", "bad-checksum"])( "stops publication on %s", (scenario) => { const calls = simulate(scenario, "", 1); expect(calls.match(/regctl image copy/g)?.length ?? 0).toBeLessThanOrEqual( 1, ); }, );