/*
RFC-1284: Unit tests for leitstand.access.suspend and
leitstand.access.resume — crash-safe suspension markers, normalization in
protect/unprotect, and per-channel failure semantics.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-1284: initial — suspension marker lifecycle coverage.
- 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.
- RFC-1327: review r1 — lock-safe reconcile gate, residue sweep, honest idempotency classes
RFC-1284
*/
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createDefaultIO } from "@warpgogol/werkstatt-shared/kernel/workspace-io";
import type { SystemState } from "@warpgogol/werkstatt-engine/schemas";
vi.mock("../../sternsystem/registry-io.ts", async (importOriginal) => {
const mod = await importOriginal();
return {
...mod,
readSystemConfigSmart: vi.fn(),
readSystemState: vi.fn(),
writeSystemState: vi.fn(),
};
});
vi.mock("../adapters/wrangler-secrets.ts", () => ({
runWranglerSecretPut: vi.fn(),
runWranglerSecretDelete: vi.fn(),
}));
const {
runLeitstandAccessSuspend,
runLeitstandAccessResume,
runLeitstandAccessProtect,
runLeitstandAccessUnprotect,
} = await import("../access-commands.ts");
const { readSystemConfigSmart, readSystemState, writeSystemState } =
await import("../../sternsystem/registry-io.ts");
const { runWranglerSecretPut, runWranglerSecretDelete } =
await import("../adapters/wrangler-secrets.ts");
function makeInput(flags: Record) {
return { flags, args: [] } as unknown as Parameters[0];
}
function makeContext(workspaceRoot: string) {
return {
io: createDefaultIO().io,
workspaceRoot,
dryRun: false,
site: undefined,
} as unknown as Parameters[1];
}
function makeState(overrides: Partial): SystemState {
return {
schemaVersion: "1.0.0",
systemId: "test-bundle",
currentMission: null,
lastRelease: null,
lastPropagated: {},
accessPin: null,
accessPinSuspended: null,
passportRequired: false,
ownershipRequired: false,
...overrides,
};
}
function makeConfig() {
return {
deployment: {
channels: {
dev: { workerName: "dev-test-bundle", url: "https://dev.example.com" },
alt: { workerName: "alt-test-bundle", url: "https://alt.example.com" },
},
},
} as unknown as Awaited>;
}
const wranglerOk = { exitCode: 0, stdout: "", stderr: "" };
beforeEach(() => {
vi.clearAllMocks();
});
describe("RFC-1284: leitstand.access.suspend", () => {
it("deletes ACCESS_PIN on dev/alt and writes the suspension marker preserving accessPin", async () => {
vi.mocked(readSystemConfigSmart).mockResolvedValueOnce(makeConfig());
vi.mocked(readSystemState).mockResolvedValueOnce(makeState({ accessPin: "1234" }));
vi.mocked(runWranglerSecretDelete).mockResolvedValue(wranglerOk);
const result = await runLeitstandAccessSuspend(
makeInput({ site: "test-bundle", by: "leitstand.certify", "operation-id": "certify-1" }),
makeContext("/tmp/test"),
);
expect(runWranglerSecretDelete).toHaveBeenCalledTimes(2);
const written = vi.mocked(writeSystemState).mock.calls[0][2];
expect(written.accessPin).toBe("1234");
expect(written.accessPinSuspended).toMatchObject({
by: "leitstand.certify",
operationId: "certify-1",
});
expect(written.accessPinSuspended!.at).toMatch(/^\d{4}-\d{2}-\d{2}T/);
expect(result.exitCode).toBeUndefined();
expect(result.data!.suspended).toEqual(written.accessPinSuspended);
});
it("refuses when accessPin is null — nothing to suspend", async () => {
vi.mocked(readSystemConfigSmart).mockResolvedValueOnce(makeConfig());
vi.mocked(readSystemState).mockResolvedValueOnce(makeState({ accessPin: null }));
await expect(
runLeitstandAccessSuspend(makeInput({ site: "test-bundle" }), makeContext("/tmp/test")),
).rejects.toThrow("nothing to suspend");
expect(runWranglerSecretDelete).not.toHaveBeenCalled();
expect(writeSystemState).not.toHaveBeenCalled();
});
it("does not write a marker when a channel delete fails", async () => {
vi.mocked(readSystemConfigSmart).mockResolvedValueOnce(makeConfig());
vi.mocked(readSystemState).mockResolvedValueOnce(makeState({ accessPin: "1234" }));
vi.mocked(runWranglerSecretDelete)
.mockResolvedValueOnce(wranglerOk)
.mockResolvedValueOnce({ exitCode: 1, stdout: "", stderr: "boom" });
const result = await runLeitstandAccessSuspend(
makeInput({ site: "test-bundle" }),
makeContext("/tmp/test"),
);
expect(
result.exitCode,
"Partial delete must exit non-zero (DNA-106) and leave no marker — drift stays ACCESS-01-visible",
).toBe(1);
expect(writeSystemState).not.toHaveBeenCalled();
expect(result.data!.suspended).toBeNull();
});
});
describe("RFC-1284: leitstand.access.resume", () => {
const marker = { at: "2026-10-15T10:00:00.000Z", by: "leitstand.certify", operationId: null };
it("re-puts ACCESS_PIN from accessPin on dev/alt and clears the marker", async () => {
vi.mocked(readSystemState).mockResolvedValueOnce(
makeState({ accessPin: "1234", accessPinSuspended: marker }),
);
vi.mocked(readSystemConfigSmart).mockResolvedValueOnce(makeConfig());
vi.mocked(runWranglerSecretPut).mockResolvedValue(wranglerOk);
const result = await runLeitstandAccessResume(
makeInput({ site: "test-bundle" }),
makeContext("/tmp/test"),
);
expect(runWranglerSecretPut).toHaveBeenCalledTimes(2);
expect(vi.mocked(runWranglerSecretPut).mock.calls[0][2]).toBe("1234");
const written = vi.mocked(writeSystemState).mock.calls[0][2];
expect(written.accessPin).toBe("1234");
expect(written.accessPinSuspended).toBeNull();
expect(result.exitCode).toBeUndefined();
expect(result.data!.resumed).toBe(true);
});
it("is a no-op when the system is not suspended", async () => {
vi.mocked(readSystemState).mockResolvedValueOnce(makeState({ accessPin: "1234" }));
const result = await runLeitstandAccessResume(
makeInput({ site: "test-bundle" }),
makeContext("/tmp/test"),
);
expect(result.exitCode).toBe(0);
expect(result.data!.resumed).toBe(false);
expect(runWranglerSecretPut).not.toHaveBeenCalled();
});
it("keeps the marker when a channel restore fails", async () => {
vi.mocked(readSystemState).mockResolvedValueOnce(
makeState({ accessPin: "1234", accessPinSuspended: marker }),
);
vi.mocked(readSystemConfigSmart).mockResolvedValueOnce(makeConfig());
vi.mocked(runWranglerSecretPut)
.mockResolvedValueOnce(wranglerOk)
.mockResolvedValueOnce({ exitCode: 1, stdout: "", stderr: "boom" });
const result = await runLeitstandAccessResume(
makeInput({ site: "test-bundle" }),
makeContext("/tmp/test"),
);
expect(
result.exitCode,
"Partial restore must exit non-zero and keep the marker so ACCESS-01 stays muted",
).toBe(1);
expect(writeSystemState).not.toHaveBeenCalled();
expect(result.data!.resumed).toBe(false);
});
it("errors when suspended but accessPin is null — cannot resume an unknown pin", async () => {
vi.mocked(readSystemState).mockResolvedValueOnce(
makeState({ accessPin: null, accessPinSuspended: marker }),
);
await expect(
runLeitstandAccessResume(makeInput({ site: "test-bundle" }), makeContext("/tmp/test")),
).rejects.toThrow("access.protect");
expect(runWranglerSecretPut).not.toHaveBeenCalled();
});
});
describe("RFC-1284: marker normalization", () => {
it("protect clears a stale suspension marker", async () => {
const marker = { at: "2026-10-15T09:00:00.000Z", by: "leitstand.certify", operationId: null };
vi.mocked(readSystemConfigSmart).mockResolvedValueOnce(makeConfig());
vi.mocked(readSystemState).mockResolvedValueOnce(
makeState({ accessPin: "1111", accessPinSuspended: marker }),
);
vi.mocked(runWranglerSecretPut).mockResolvedValue(wranglerOk);
await runLeitstandAccessProtect(
makeInput({ site: "test-bundle", pin: "5678" }),
makeContext("/tmp/test"),
);
const written = vi.mocked(writeSystemState).mock.calls[0][2];
expect(written.accessPin).toBe("5678");
expect(
written.accessPinSuspended,
"protect must normalize accessPinSuspended to null — a freshly asserted pin is not suspended",
).toBeNull();
});
it("unprotect clears both accessPin and the suspension marker", async () => {
const marker = { at: "2026-10-15T09:00:00.000Z", by: "operator", operationId: null };
vi.mocked(readSystemConfigSmart).mockResolvedValueOnce(makeConfig());
vi.mocked(readSystemState).mockResolvedValueOnce(
makeState({ accessPin: "1111", accessPinSuspended: marker }),
);
vi.mocked(runWranglerSecretDelete).mockResolvedValue(wranglerOk);
await runLeitstandAccessUnprotect(makeInput({ site: "test-bundle" }), makeContext("/tmp/test"));
const written = vi.mocked(writeSystemState).mock.calls[0][2];
expect(written.accessPin).toBeNull();
expect(
written.accessPinSuspended,
"unprotect must dissolve the marker — permanent unprotection leaves no suspension",
).toBeNull();
});
});
describe("RFC-1327: protect rerun convergence", () => {
it("protect without --pin on an already-pinned site is a no-op, not a rotation", async () => {
vi.mocked(readSystemState).mockResolvedValueOnce(makeState({ accessPin: "1111" }));
const result = await runLeitstandAccessProtect(
makeInput({ site: "test-bundle" }),
makeContext("/tmp/test"),
);
expect(result.data!.pin).toBe("1111");
expect(result.summary).toContain("already protected");
expect(
runWranglerSecretPut,
"no --pin + recorded accessPin must not rotate the deployed secret",
).not.toHaveBeenCalled();
expect(writeSystemState).not.toHaveBeenCalled();
});
it("explicit --pin still rotates even when a PIN is recorded", async () => {
vi.mocked(readSystemConfigSmart).mockResolvedValueOnce(makeConfig());
vi.mocked(readSystemState).mockResolvedValueOnce(makeState({ accessPin: "1111" }));
vi.mocked(runWranglerSecretPut).mockResolvedValue(wranglerOk);
const result = await runLeitstandAccessProtect(
makeInput({ site: "test-bundle", pin: "9999" }),
makeContext("/tmp/test"),
);
expect(result.data!.pin).toBe("9999");
expect(runWranglerSecretPut).toHaveBeenCalled();
});
});