/*
RFC-1284 AC-12: unit coverage for isProtectedLiveTarget — the predicate that
decides whether certify's measurement target is a protected live host
(channel target always; explicit --base-url when its hostname matches a
configured dev/alt channel URL, with a ^(dev|alt)[.-] prefix fallback for
hosts absent from channel config; candidate-preview never qualifies).
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-1284: initial — AC-12 predicate coverage (REVIEW-CODE-2026-10-15-02 F6).
- RFC-1284: fix review REVIEW-CODE-2026-10-15-02: RFC-1284 — single-store marker, flag=false proceed, surfaced reconcile
F1: marker store unified on the git-tracked cache clone — access commands,
certify entry check, and deploy reconcile all use non-smart
readSystemState/writeSystemState (decisions Q-6); the mission-window
blindness and the DNA-106 false-resume are gone.
F2: --auto-manage-pin=false + suspension at entry skips entry-resume and
proceeds on the open channel (decisions Q-7) — RFC/AC-8 text amended.
F3: accessReconcile surfaced in data + summary of dev-deploy/propagate.
F4: CHANGE_SUMMARY items on all touched files.
F5: sternsystem.validate declares ACCESS-01/02 + system-state.yaml reads.
F6: isProtectedLiveTarget exported and covered (AC-12 probe repointed).
F7: fresh-read ordering proven — suspension opened mid-deploy suppresses
the re-assert.
*/
import { describe, it, expect, vi, beforeEach } from "vitest";
vi.mock("../../sternsystem/registry-io.ts", async (importOriginal) => {
const original = await importOriginal();
return {
...original,
readSystemConfigSmart: vi.fn(),
};
});
import { readSystemConfigSmart } from "../../sternsystem/registry-io.ts";
import { isProtectedLiveTarget } from "../certify.ts";
import type { SystemConfig } from "@warpgogol/werkstatt-engine/schemas";
const readConfigMock = vi.mocked(readSystemConfigSmart);
function configWithChannels(devUrl?: string, altUrl?: string): SystemConfig {
return {
id: "acme",
deployment: {
channels: {
dev: { url: devUrl },
alt: { url: altUrl },
},
},
} as SystemConfig;
}
describe("isProtectedLiveTarget (RFC-1284 AC-12)", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("--target channel is always a protected live target", async () => {
await expect(isProtectedLiveTarget(undefined, "channel", "/ws", "acme")).resolves.toBe(true);
expect(readConfigMock).not.toHaveBeenCalled();
});
it("candidate target without --base-url is never protected", async () => {
await expect(isProtectedLiveTarget(undefined, "candidate", "/ws", "acme")).resolves.toBe(false);
expect(readConfigMock).not.toHaveBeenCalled();
});
it("--base-url matching the dev channel hostname is protected", async () => {
readConfigMock.mockResolvedValue(
configWithChannels("https://dev-acme.workers.dev", "https://alt-acme.workers.dev"),
);
await expect(
isProtectedLiveTarget("https://dev-acme.workers.dev/some/path", "candidate", "/ws", "acme"),
).resolves.toBe(true);
});
it("--base-url matching the alt channel hostname is protected", async () => {
readConfigMock.mockResolvedValue(
configWithChannels("https://dev-acme.workers.dev", "https://alt-acme.workers.dev"),
);
await expect(
isProtectedLiveTarget("https://alt-acme.workers.dev", "candidate", "/ws", "acme"),
).resolves.toBe(true);
});
it("--base-url on an unrelated host is not protected", async () => {
readConfigMock.mockResolvedValue(
configWithChannels("https://dev-acme.workers.dev", "https://alt-acme.workers.dev"),
);
await expect(
isProtectedLiveTarget("http://localhost:8787", "candidate", "/ws", "acme"),
).resolves.toBe(false);
});
it("falls back to the dev-/alt- prefix when channel config is unreadable", async () => {
readConfigMock.mockRejectedValue(new Error("no systems-cache"));
await expect(
isProtectedLiveTarget("https://dev-warpgogol-com.acc.workers.dev", "candidate", "/ws", "acme"),
).resolves.toBe(true);
await expect(
isProtectedLiveTarget("https://api.example.com", "candidate", "/ws", "acme"),
).resolves.toBe(false);
});
it("malformed --base-url is not protected", async () => {
await expect(isProtectedLiveTarget("not-a-url", "candidate", "/ws", "acme")).resolves.toBe(false);
expect(readConfigMock).not.toHaveBeenCalled();
});
});