54 lines
1.5 KiB
TypeScript
54 lines
1.5 KiB
TypeScript
import { readFileSync } from "node:fs";
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
type RunbookSpecification = Readonly<{
|
|
triggerKinds: string[];
|
|
containment: string;
|
|
window: string;
|
|
escalation: string[];
|
|
recoveryEvidence: string[];
|
|
negativeFixture: string;
|
|
gateId: string;
|
|
}>;
|
|
|
|
type RunbookDocument = Readonly<{
|
|
runbooks: Record<string, RunbookSpecification>;
|
|
}>;
|
|
|
|
describe("operational runbook contract", () => {
|
|
const document = JSON.parse(
|
|
readFileSync("config/runbooks/runbooks.json", "utf8"),
|
|
) as RunbookDocument;
|
|
|
|
it("defines all five runbooks with four machine-checkable contract axes", () => {
|
|
expect(Object.keys(document.runbooks)).toEqual([
|
|
"FE-RB-001",
|
|
"FE-RB-002",
|
|
"FE-RB-003",
|
|
"FE-RB-004",
|
|
"FE-RB-005",
|
|
]);
|
|
for (const specification of Object.values(document.runbooks)) {
|
|
expect(specification.triggerKinds.length).toBeGreaterThan(0);
|
|
expect(specification.containment).toEqual(expect.any(String));
|
|
expect(specification.window).toEqual(expect.any(String));
|
|
expect(specification.escalation.length).toBeGreaterThanOrEqual(2);
|
|
expect(specification.recoveryEvidence).toHaveLength(4);
|
|
expect(specification.negativeFixture).toEqual(expect.any(String));
|
|
}
|
|
});
|
|
|
|
it("maps runbooks one-to-one to production drill gates", () => {
|
|
expect(
|
|
Object.values(document.runbooks).map((runbook) => runbook.gateId),
|
|
).toEqual([
|
|
"FE-GATE-021",
|
|
"FE-GATE-022",
|
|
"FE-GATE-023",
|
|
"FE-GATE-024",
|
|
"FE-GATE-025",
|
|
]);
|
|
});
|
|
});
|