feat: add dev durable runtime provisioning gates
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
buildDevRuntimePostflightReport,
|
||||
parseArgs
|
||||
} from "./dev-runtime-postflight.mjs";
|
||||
|
||||
test("check mode is source-only and does not attempt live reads or M3 writes", async () => {
|
||||
const report = await buildDevRuntimePostflightReport(parseArgs(["--check"]), {
|
||||
m3SourceBuilder: async () => ({
|
||||
mode: "source-static",
|
||||
summary: {
|
||||
status: "pass",
|
||||
classification: "source_static_contract_checked",
|
||||
trustedGreen: false,
|
||||
result: "source checked"
|
||||
}
|
||||
}),
|
||||
now: () => "2026-05-23T00:00:00.000Z"
|
||||
});
|
||||
|
||||
assert.equal(report.conclusion.status, "pass");
|
||||
assert.equal(report.actions.healthLiveReadAttempted, false);
|
||||
assert.equal(report.actions.v1ReadAttempted, false);
|
||||
assert.equal(report.actions.m3MutationAttempted, false);
|
||||
assert.equal(report.safety.secretValuesPrinted, false);
|
||||
});
|
||||
|
||||
test("live mode refuses without explicit DEV confirmations", async () => {
|
||||
const report = await buildDevRuntimePostflightReport(parseArgs(["--live"]), {
|
||||
now: () => "2026-05-23T00:00:00.000Z"
|
||||
});
|
||||
|
||||
assert.equal(report.conclusion.status, "blocked");
|
||||
assert.equal(report.safetyRefusal, true);
|
||||
assert.equal(report.actions.healthLiveReadAttempted, false);
|
||||
assert.equal(report.actions.m3MutationAttempted, false);
|
||||
});
|
||||
|
||||
test("live mode skips M3 writes when /health/live durable runtime is blocked", async () => {
|
||||
const report = await buildDevRuntimePostflightReport(
|
||||
parseArgs(["--live", "--confirm-dev", "--confirmed-non-production"]),
|
||||
{
|
||||
httpGetJson: async (url) => ({ ok: true, status: 200, json: apiPayload({ ready: url.endsWith("/v1") }) }),
|
||||
m3Runner: async () => {
|
||||
throw new Error("M3 runner should not run before durable readiness is green");
|
||||
},
|
||||
now: () => "2026-05-23T00:00:00.000Z"
|
||||
}
|
||||
);
|
||||
|
||||
assert.equal(report.conclusion.status, "blocked");
|
||||
assert.equal(report.actions.healthLiveReadAttempted, true);
|
||||
assert.equal(report.actions.v1ReadAttempted, true);
|
||||
assert.equal(report.actions.m3MutationAttempted, false);
|
||||
assert.equal(report.m3.status, "not_run");
|
||||
assert.equal(report.blockers.some((blocker) => blocker.scope === "api-health-live"), true);
|
||||
assert.equal(JSON.stringify(report).includes("postgresql://"), false);
|
||||
});
|
||||
|
||||
test("live mode requires /v1 durable readiness before M3 writes", async () => {
|
||||
const report = await buildDevRuntimePostflightReport(
|
||||
parseArgs(["--live", "--confirm-dev", "--confirmed-non-production"]),
|
||||
{
|
||||
httpGetJson: async (url) => ({ ok: true, status: 200, json: apiPayload({ ready: !url.endsWith("/v1") }) }),
|
||||
m3Runner: async () => {
|
||||
throw new Error("M3 runner should not run when /v1 is blocked");
|
||||
},
|
||||
now: () => "2026-05-23T00:00:00.000Z"
|
||||
}
|
||||
);
|
||||
|
||||
assert.equal(report.conclusion.status, "blocked");
|
||||
assert.equal(report.actions.m3MutationAttempted, false);
|
||||
assert.equal(report.blockers.some((blocker) => blocker.scope === "api-v1"), true);
|
||||
});
|
||||
|
||||
test("live mode records M3 true/false durable green evidence", async () => {
|
||||
const report = await buildDevRuntimePostflightReport(
|
||||
parseArgs(["--live", "--confirm-dev", "--confirmed-non-production"]),
|
||||
{
|
||||
httpGetJson: async () => ({ ok: true, status: 200, json: apiPayload({ ready: true }) }),
|
||||
m3Runner: async () => m3GreenReport(),
|
||||
now: () => "2026-05-23T00:00:00.000Z"
|
||||
}
|
||||
);
|
||||
|
||||
assert.equal(report.conclusion.status, "pass");
|
||||
assert.equal(report.actions.m3MutationAttempted, true);
|
||||
assert.equal(report.actions.m3MutationAllowed, true);
|
||||
assert.equal(report.m3.trustedGreen, true);
|
||||
assert.equal(report.m3.operationCount, 4);
|
||||
assert.deepEqual(report.m3.operations.map((operation) => operation.resultValue), [true, true, false, false]);
|
||||
assert.equal(report.blockers.length, 0);
|
||||
});
|
||||
|
||||
test("live mode blocks when M3 operation evidence is not durable green", async () => {
|
||||
const m3 = m3GreenReport();
|
||||
m3.liveOperations[1].evidenceState.durable = false;
|
||||
const report = await buildDevRuntimePostflightReport(
|
||||
parseArgs(["--live", "--confirm-dev", "--confirmed-non-production"]),
|
||||
{
|
||||
httpGetJson: async () => ({ ok: true, status: 200, json: apiPayload({ ready: true }) }),
|
||||
m3Runner: async () => m3,
|
||||
now: () => "2026-05-23T00:00:00.000Z"
|
||||
}
|
||||
);
|
||||
|
||||
assert.equal(report.conclusion.status, "blocked");
|
||||
assert.equal(report.blockers.some((blocker) => blocker.scope === "m3-durable-evidence"), true);
|
||||
});
|
||||
|
||||
function apiPayload({ ready }) {
|
||||
return {
|
||||
serviceId: "hwlab-cloud-api",
|
||||
environment: "dev",
|
||||
status: ready ? "ready" : "blocked",
|
||||
ready,
|
||||
db: {
|
||||
ready,
|
||||
connected: ready,
|
||||
liveDbEvidence: ready,
|
||||
endpointSource: "secret-url-host",
|
||||
connectionResult: ready ? "connected" : "connected",
|
||||
runtimeReadiness: {
|
||||
ready,
|
||||
status: ready ? "ready" : "blocked",
|
||||
blocker: ready ? null : "runtime_durable_adapter_auth_blocked",
|
||||
queryResult: ready ? "durable_readiness_ready" : "auth_blocked",
|
||||
requiredEvidence: "runtime_adapter_schema_migration_read_query"
|
||||
}
|
||||
},
|
||||
runtime: {
|
||||
adapter: "postgres",
|
||||
durable: ready,
|
||||
durableRequested: true,
|
||||
ready,
|
||||
status: ready ? "ready" : "blocked",
|
||||
blocker: ready ? null : "runtime_durable_adapter_auth_blocked",
|
||||
liveRuntimeEvidence: ready,
|
||||
durabilityContract: {
|
||||
requiredEvidence: "runtime_adapter_schema_migration_read_query",
|
||||
blockedLayer: ready ? null : "auth"
|
||||
},
|
||||
gates: {
|
||||
ssl: gate(true),
|
||||
auth: gate(ready, "runtime_durable_adapter_auth_blocked"),
|
||||
schema: gate(ready),
|
||||
migration: gate(ready),
|
||||
durability: gate(ready)
|
||||
}
|
||||
},
|
||||
readiness: {
|
||||
ready,
|
||||
status: ready ? "ready" : "blocked",
|
||||
durability: {
|
||||
ready,
|
||||
blockedLayer: ready ? null : "auth"
|
||||
}
|
||||
},
|
||||
blockerCodes: ready ? []
|
||||
: ["runtime_durable_adapter_auth_blocked"]
|
||||
};
|
||||
}
|
||||
|
||||
function gate(ready, blocker = null) {
|
||||
return {
|
||||
checked: true,
|
||||
ready,
|
||||
status: ready ? "ready" : "blocked",
|
||||
blocker: ready ? null : blocker
|
||||
};
|
||||
}
|
||||
|
||||
function m3GreenReport() {
|
||||
const values = [true, true, false, false];
|
||||
return {
|
||||
mode: "dev-live",
|
||||
summary: {
|
||||
status: "pass",
|
||||
classification: "trusted_green",
|
||||
trustedGreen: true,
|
||||
result: "DEV-LIVE M3 IO control path and durable trusted records are green."
|
||||
},
|
||||
liveOperations: values.map((value, index) => ({
|
||||
id: ["write-do1-true", "read-di1-true", "write-do1-false", "read-di1-false"][index],
|
||||
action: index % 2 === 0 ? "do.write" : "di.read",
|
||||
status: "succeeded",
|
||||
operationId: `op_${index}`,
|
||||
traceId: `trc_${index}`,
|
||||
auditId: `aud_${index}`,
|
||||
evidenceId: `ev_${index}`,
|
||||
resultValue: value,
|
||||
evidenceState: {
|
||||
status: "green",
|
||||
durable: true,
|
||||
sourceKind: "DEV-LIVE"
|
||||
}
|
||||
}))
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user