import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { runCyberPreflight } from "./cyber-preflight.js"; const roots: string[] = []; afterEach(() => { for (const root of roots.splice(0)) fs.rmSync(root, { recursive: true, force: true }); }); function tmpFile(): string { const root = fs.mkdtempSync(path.join(os.tmpdir(), "fable-cyber-preflight-")); roots.push(root); return path.join(root, "receipt.json"); } function runner(failNames: string[] = []) { return (_command: string, args: string[]) => { const joined = args.join(" "); const shouldFail = failNames.some((name) => joined.includes(name)); return { status: shouldFail ? 22 : 0, stdout: shouldFail ? "" : "ok token=SHOULD_REDACT", stderr: shouldFail ? "curl: returned 404 Authorization: token SHOULD_REDACT" : "", }; }; } describe("cyber preflight", () => { it("allows read-only when required live checks pass", () => { const receipt = runCyberPreflight({ host: "127.0.0.1", runner: runner(), now: new Date("2026-06-16T00:00:00.000Z") }); expect(receipt.decision).toBe("allow_read_only"); expect(receipt.deploy_allowed).toBe(false); expect(receipt.checks).toHaveLength(5); }); it("fails closed when a required endpoint is missing", () => { const receipt = runCyberPreflight({ host: "127.0.0.1", runner: runner(["factory-status"]) }); expect(receipt.decision).toBe("fail_closed"); expect(receipt.deploy_allowed).toBe(false); }); it("writes a redacted receipt", () => { const out = tmpFile(); runCyberPreflight({ host: "127.0.0.1", out, runner: runner(["health"]) }); const text = fs.readFileSync(out, "utf-8"); expect(text).toContain("[REDACTED]"); expect(text).not.toContain("SHOULD_REDACT"); }); });