feat(ql3): gate primary on shadow capture evidence

This commit is contained in:
whyour
2026-08-19 03:27:32 +08:00
parent c60a86d1bf
commit be98d6753b
28 changed files with 2227 additions and 30 deletions
@@ -25,6 +25,34 @@ function loadResult(status, mode = 'off') {
sourcePath: '/data/config/qinglong3-rollout.json',
status,
},
...(status === 'accepted'
? {
primaryGateReceipt: {
schema: 'qinglong/legacy-shadow-primary-gate@v1',
schemaVersion: 1,
profile: 'standalone',
origin: 'manual',
generatedAtMs: NOW - 2_000,
assessment: 'eligible',
window: {
startInclusiveMs: NOW - 10_000,
endExclusiveMs: NOW - 5_000,
},
counts: {
admitted: 32,
captured: 32,
terminalScanned: 32,
terminalMatched: 32,
},
evidence: {
captureSha256: 'a'.repeat(64),
terminalSha256: 'b'.repeat(64),
resourceSha256: 'c'.repeat(64),
},
violations: [],
},
}
: {}),
};
}
@@ -171,6 +199,27 @@ test('accepted bootstrap audits a lazy stack import failure without installing',
assert.deepEqual(calls, ['load-stack', 'audit:failed']);
});
test('accepted bootstrap rejects a Primary receipt for another Profile before loading', async () => {
const calls = [];
const load = loadResult('accepted', 'primary');
load.primaryGateReceipt.profile = 'edge';
await assert.rejects(
bootstrapDefaultManualPrimaryRuntime({
load: async () => load,
deploymentProfile: 'standalone',
async loadStack() {
calls.push('load-stack');
throw new Error('must remain lazy');
},
audit(record) {
calls.push(`audit:${record.activation}`);
},
}),
/does not authorize this deployment Profile/,
);
assert.deepEqual(calls, ['audit:failed']);
});
test('disabled bootstrap stays inert even with an invalid deployment profile', async () => {
const previous = process.env.QL_DEPLOYMENT_PROFILE;
process.env.QL_DEPLOYMENT_PROFILE = 'invalid-profile';
@@ -219,7 +268,7 @@ test('accepted bootstrap rejects and audits an invalid deployment profile', asyn
}),
/QL_DEPLOYMENT_PROFILE is invalid/,
);
assert.deepEqual(calls, ['load-stack', 'audit:selected', 'audit:failed']);
assert.deepEqual(calls, ['audit:failed']);
} finally {
if (previous === undefined) delete process.env.QL_DEPLOYMENT_PROFILE;
else process.env.QL_DEPLOYMENT_PROFILE = previous;
@@ -0,0 +1,162 @@
require('ts-node/register/transpile-only');
const assert = require('node:assert/strict');
const fs = require('node:fs/promises');
const os = require('node:os');
const path = require('node:path');
const { afterEach, test } = require('node:test');
const {
LegacyShadowCaptureAuthority,
} = require('../../back/runtime/application/legacyShadowCaptureAuthority');
const {
bootstrapLegacyShadowCaptureEvidence,
} = require('../../back/runtime/adapters/legacy/bootstrapLegacyShadowCaptureEvidence');
const directories = [];
function startup(state = 'reconciled') {
if (state !== 'reconciled') return { state };
return {
state: 'reconciled',
profile: 'edge',
origins: 1,
summary: {},
metrics: {},
report: {
schema: 'qinglong/legacy-shadow-startup-difference-report@v1',
schemaVersion: 1,
profile: 'edge',
assessment: 'converged',
configuredOriginCount: 1,
budget: { pageSize: 8, maxPages: 1, maxCandidates: 8 },
coverage: {
pages: 1,
scanned: 0,
stopReason: 'complete',
remaining: false,
resumeAvailable: false,
},
outcomes: {
completed: 0,
cancelled: 0,
abandoned: 0,
markedLost: 0,
repaired: 0,
pending: 0,
ambiguous: 0,
skipped: 0,
failed: 0,
},
byOrigin: [
{
origin: 'manual',
scanned: 0,
completed: 0,
cancelled: 0,
abandoned: 0,
markedLost: 0,
repaired: 0,
pending: 0,
ambiguous: 0,
skipped: 0,
failed: 0,
},
],
},
};
}
afterEach(async () => {
await Promise.all(
directories
.splice(0)
.map((directory) => fs.rm(directory, { recursive: true, force: true })),
);
});
test('exports one qualified no-identity capture report on clean shutdown', async () => {
let now = 1_750_300_000_000;
const authority = new LegacyShadowCaptureAuthority(
{ now: () => now },
'019f75d2-3333-7333-8333-333333333333',
);
let evidence;
const audits = [];
const handle = await bootstrapLegacyShadowCaptureEvidence({
startup: startup(),
origins: ['manual'],
profile: 'edge',
outputPath: '/private/evidence.json',
snapshot: (origins) => authority.snapshot(origins),
async write(_outputPath, value) {
evidence = value;
},
audit: (record) => audits.push(record),
});
for (let index = 0; index < 8; index += 1) {
authority.admit('manual').captured();
}
now += 1_000;
assert.equal(handle.active, true);
assert.equal((await handle.close()).state, 'exported');
assert.deepEqual(await handle.close(), audits.at(-1));
assert.equal(evidence.qualification.passed, true);
assert.equal(evidence.capture.totals.admitted, 8);
assert.equal(evidence.capture.capturePermille, 1_000);
assert.doesNotMatch(JSON.stringify(evidence), /taskId|runId|attemptId|pid/);
assert.deepEqual(
audits.map((record) => record.state),
['armed', 'exported'],
);
});
test('writes owner-private evidence once and refuses overwrite', async () => {
const directory = await fs.mkdtemp(path.join(os.tmpdir(), 'ql3-capture-'));
directories.push(directory);
const outputPath = path.join(directory, 'capture.json');
let now = 1_750_300_000_000;
const authority = new LegacyShadowCaptureAuthority(
{ now: () => now },
'019f75d2-4444-7444-8444-444444444444',
);
const options = {
startup: startup(),
origins: ['manual'],
profile: 'edge',
outputPath,
snapshot: (origins) => authority.snapshot(origins),
audit() {},
};
const first = await bootstrapLegacyShadowCaptureEvidence(options);
authority.admit('manual').captured();
now += 1_000;
assert.equal((await first.close()).state, 'exported');
assert.equal((await fs.stat(outputPath)).mode & 0o777, 0o600);
const second = await bootstrapLegacyShadowCaptureEvidence(options);
authority.admit('manual').captured();
now += 1_000;
assert.equal((await second.close()).state, 'failed');
});
test('stays inert without an explicit path and rejects missing startup authority', async () => {
const disabled = await bootstrapLegacyShadowCaptureEvidence({
startup: { state: 'disabled' },
origins: [],
profile: 'edge',
audit() {},
});
assert.equal(disabled.active, false);
assert.equal((await disabled.close()).state, 'disabled');
const failed = await bootstrapLegacyShadowCaptureEvidence({
startup: { state: 'incomplete' },
origins: ['manual'],
profile: 'edge',
outputPath: '/private/evidence.json',
audit() {},
});
assert.equal(failed.active, false);
assert.equal((await failed.close()).state, 'failed');
});
@@ -319,6 +319,9 @@ test('HTTP startup orders Shadow recovery after Legacy normalization and before
const shadowRecovery = source.indexOf(
'await bootstrapLegacyShadowStartupReconciliation()',
);
const captureEvidence = source.indexOf(
'await bootstrapLegacyShadowCaptureEvidence({',
);
const primaryActivation = source.indexOf(
'await bootstrapDefaultManualPrimaryRuntime()',
);
@@ -328,6 +331,7 @@ test('HTTP startup orders Shadow recovery after Legacy normalization and before
assert.equal(legacyNormalization >= 0, true);
assert.equal(legacyNormalization < shadowRecovery, true);
assert.equal(shadowRecovery < primaryActivation, true);
assert.equal(shadowRecovery < captureEvidence, true);
assert.equal(captureEvidence < primaryActivation, true);
assert.equal(primaryActivation < listen, true);
});
@@ -0,0 +1,113 @@
require('ts-node/register/transpile-only');
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
LegacyShadowCaptureAuthority,
createLegacyShadowCaptureReport,
} = require('../../back/runtime/application/legacyShadowCaptureAuthority');
const EPOCH = '019f75d2-1111-7111-8111-111111111111';
function fixture() {
let now = 1_750_200_000_000;
const authority = new LegacyShadowCaptureAuthority({ now: () => now }, EPOCH);
return {
authority,
advance(milliseconds = 1_000) {
now += milliseconds;
},
};
}
test('creates a conserved origin-scoped capture window', () => {
const value = fixture();
const before = value.authority.snapshot(['manual']);
for (let index = 0; index < 8; index += 1) {
value.authority.admit('manual').captured();
}
value.advance();
const after = value.authority.snapshot(['manual']);
const report = createLegacyShadowCaptureReport(
'edge',
['manual'],
before,
after,
);
assert.equal(report.assessment, 'captured');
assert.equal(report.totals.admitted, 8);
assert.equal(report.totals.captured, 8);
assert.equal(report.totals.failed, 0);
assert.equal(report.totals.pending, 0);
assert.equal(report.capturePermille, 1_000);
assert.equal(JSON.stringify(report).includes('task'), false);
});
test('separates fixed failure stages and incomplete admissions', () => {
const value = fixture();
const before = value.authority.snapshot(['manual', 'scheduled_node']);
value.authority.admit('manual').failed('fact');
value.authority.admit('manual').failed('accept');
value.authority.admit('scheduled_node');
value.advance();
const report = createLegacyShadowCaptureReport(
'standalone',
['manual', 'scheduled_node'],
before,
value.authority.snapshot(['manual', 'scheduled_node']),
);
assert.equal(report.assessment, 'incomplete');
assert.deepEqual(report.totals, {
admitted: 3,
captured: 0,
failed: 2,
pending: 1,
failures: { fact: 1, observer: 0, initialization: 0, accept: 1 },
});
});
test('rejects cross-epoch, pending-baseline and incomplete-origin evidence', () => {
const left = fixture();
const right = new LegacyShadowCaptureAuthority(
{ now: () => 1_750_200_001_000 },
'019f75d2-2222-7222-8222-222222222222',
);
assert.throws(
() =>
createLegacyShadowCaptureReport(
'edge',
['manual'],
left.authority.snapshot(['manual']),
right.snapshot(['manual']),
),
/cross process epochs/,
);
left.authority.admit('manual');
const pending = left.authority.snapshot(['manual']);
left.advance();
assert.throws(
() =>
createLegacyShadowCaptureReport(
'edge',
['manual'],
pending,
left.authority.snapshot(['manual']),
),
/starts with pending/,
);
assert.throws(
() =>
createLegacyShadowCaptureReport(
'edge',
['manual', 'boot'],
left.authority.snapshot(['manual']),
left.authority.snapshot(['manual']),
),
/window must be non-empty|coverage is incomplete/,
);
});
+231
View File
@@ -0,0 +1,231 @@
require('ts-node/register/transpile-only');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { afterEach, test } = require('node:test');
const {
createLegacyShadowPrimaryGateReceipt,
parseLegacyShadowPrimaryGateReceipt,
} = require('../../back/runtime/domain/legacyShadowPrimaryGate');
const {
parseArguments,
readEvidence,
run,
} = require('../../scripts/ql3-legacy-shadow-primary-gate.cjs');
const START = 1_750_400_000_000;
const END = START + 60_000;
const GENERATED = END + 6 * 60_000;
const directories = [];
function captureEvidence(admitted = 8) {
const outcomes = {
completed: 0,
cancelled: 0,
abandoned: 0,
markedLost: 0,
repaired: 0,
pending: 0,
ambiguous: 0,
skipped: 0,
failed: 0,
};
return {
schema: 'qinglong/legacy-shadow-capture-evidence@v1',
profile: 'edge',
startup: {
schema: 'qinglong/legacy-shadow-startup-difference-report@v1',
profile: 'edge',
assessment: 'converged',
configuredOriginCount: 1,
coverage: { remaining: false },
outcomes,
byOrigin: [{ origin: 'manual', scanned: 0, ...outcomes }],
},
capture: {
schema: 'qinglong/legacy-shadow-capture-report@v1',
profile: 'edge',
assessment: 'captured',
epoch: '019f75d2-5555-7555-8555-555555555555',
window: {
basis: 'process_local_legacy_admission',
startInclusiveMs: START,
endExclusiveMs: END,
},
configuredOriginCount: 1,
totals: {
admitted,
captured: admitted,
failed: 0,
pending: 0,
failures: { fact: 0, observer: 0, initialization: 0, accept: 0 },
},
byOrigin: [
{
origin: 'manual',
admitted,
captured: admitted,
failed: 0,
pending: 0,
failures: {
fact: 0,
observer: 0,
initialization: 0,
accept: 0,
},
},
],
capturePermille: 1_000,
},
qualification: {
passed: true,
startupConverged: true,
originCoverageExact: true,
captureComplete: true,
},
};
}
function terminal(scanned = 8) {
return {
schema: 'qinglong/legacy-shadow-terminal-difference-report@v1',
profile: 'edge',
observedAtMs: GENERATED - 1,
window: {
basis: 'shadow_run_created_at',
startInclusiveMs: START,
endExclusiveMs: END,
minimumSettlingAgeMs: 300_000,
closed: true,
},
coverage: {
direction: 'shadow_to_legacy',
cohort: 'legacy_owned_shadow_runs',
legacyWithoutShadow: 'not_measured',
},
scanned,
remaining: false,
evidenceComplete: true,
assessment: 'matched',
counts: { matched: scanned },
byOrigin: [{ origin: 'manual', scanned, matched: scanned }],
terminalAgreementPermille: 1_000,
fullyComparablePermille: 1_000,
};
}
function resource() {
return {
schemaVersion: 1,
fixture: 'qinglong/legacy-shadow-resource-rollback-evidence@v1',
profile: 'edge',
workload: { mode: 'full', runtime: 'compiled_backend' },
rollback: {
performed: true,
legacyContinued: true,
shadowWritesStopped: true,
databaseIntegrity: 'ok',
},
qualification: { passed: true, violations: [] },
};
}
function input(overrides = {}) {
return {
profile: 'edge',
generatedAtMs: GENERATED,
capture: captureEvidence(),
terminal: terminal(),
resource: resource(),
...overrides,
};
}
afterEach(() => {
for (const directory of directories.splice(0)) {
fs.rmSync(directory, { recursive: true, force: true });
}
});
test('combines capture, startup, terminal and rollback evidence into eligibility', () => {
const receipt = createLegacyShadowPrimaryGateReceipt(input());
assert.equal(receipt.assessment, 'eligible');
assert.deepEqual(receipt.violations, []);
assert.deepEqual(receipt.counts, {
admitted: 8,
captured: 8,
terminalScanned: 8,
terminalMatched: 8,
});
assert.deepEqual(parseLegacyShadowPrimaryGateReceipt(receipt), receipt);
});
test('fails closed for an undersized cohort, terminal drift and audit-only rollback', () => {
const capture = captureEvidence(7);
const terminalReport = terminal(6);
const rollback = resource();
rollback.workload.mode = 'audit-only';
const receipt = createLegacyShadowPrimaryGateReceipt(
input({ capture, terminal: terminalReport, resource: rollback }),
);
assert.equal(receipt.assessment, 'ineligible');
assert.deepEqual(receipt.violations, [
'capture_sample_budget_invalid',
'terminal_not_matched',
'resource_not_compiled_full_rollback',
]);
assert.throws(
() =>
parseLegacyShadowPrimaryGateReceipt({
...receipt,
assessment: 'eligible',
}),
/invalid/,
);
});
test('CLI reads no-follow bounded inputs and publishes a no-replace receipt', () => {
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'ql3-primary-gate-'));
directories.push(directory);
const paths = Object.fromEntries(
['capture', 'terminal', 'resource', 'output'].map((name) => [
name,
path.join(directory, `${name}.json`),
]),
);
fs.writeFileSync(paths.capture, `${JSON.stringify(captureEvidence())}\n`, {
mode: 0o600,
});
fs.writeFileSync(paths.terminal, `${JSON.stringify(terminal())}\n`, {
mode: 0o600,
});
fs.writeFileSync(paths.resource, `${JSON.stringify(resource())}\n`, {
mode: 0o600,
});
const options = parseArguments([
'--profile=edge',
`--capture=${paths.capture}`,
`--terminal=${paths.terminal}`,
`--resource=${paths.resource}`,
`--output=${paths.output}`,
`--generated-at-ms=${GENERATED}`,
]);
const receipt = run(options);
assert.equal(receipt.assessment, 'eligible');
assert.equal(
parseLegacyShadowPrimaryGateReceipt(readEvidence(paths.output).value)
.assessment,
'eligible',
);
assert.equal(fs.statSync(paths.output).mode & 0o777, 0o600);
assert.throws(() => run(options), /EEXIST/);
const symlink = path.join(directory, 'capture-link.json');
fs.symlinkSync(paths.capture, symlink);
assert.throws(() => readEvidence(symlink), /ELOOP|symbolic/i);
});
+2
View File
@@ -125,6 +125,7 @@ test('serializes a successful observed process lifecycle without starting it', a
failure: (failure) => failures.push(failure),
});
const observation = observer.begin(acceptedFact());
assert.equal(await observation.captureSettled(), 'captured');
observation.spawned({
atMs: ACCEPTED_AT_MS + 1,
pid: 4242,
@@ -231,6 +232,7 @@ test('is default-off, fail-open, and rejects primary ownership', async () => {
failure: (failure) => failures.push(failure),
});
const failed = shadow.begin(acceptedFact());
assert.equal(await failed.captureSettled(), 'failed');
failed.spawned({ atMs: ACCEPTED_AT_MS + 1 });
failed.exited({ atMs: ACCEPTED_AT_MS + 2, exitCode: 0 });
await failed.settled();
@@ -146,6 +146,12 @@ test(
assert.equal(report.rollback.enabled.runDelta, 1);
assert.equal(report.rollback.enabled.defaultObserverLoaded, true);
assert.equal(report.rollback.enabled.repositoryLoaded, true);
assert.equal(report.rollback.enabled.capture.assessment, 'captured');
assert.equal(report.rollback.enabled.capture.totals.admitted, 1);
assert.equal(report.rollback.enabled.capture.totals.captured, 1);
assert.equal(report.rollback.enabled.capture.totals.failed, 0);
assert.equal(report.rollback.enabled.capture.totals.pending, 0);
assert.equal(report.rollback.enabled.capture.byOrigin[0].origin, 'system');
assert.deepEqual(report.rollback.off.configuredOrigins, []);
assert.equal(report.rollback.off.legacyExitCode, 0);
assert.equal(report.rollback.off.runDelta, 0);
+17 -2
View File
@@ -15,13 +15,19 @@ const NOW = 1_750_000_000_000;
function enabledManifest(overrides = {}) {
return {
schemaVersion: 1,
schemaVersion: 2,
revision: 'manual-primary-canary-1',
enabled: true,
approvedBy: 'operator:admin',
approvedAtMs: NOW - 1_000,
expiresAtMs: NOW + 60_000,
rollbackPlanRef: 'docs/runbooks/disable-primary.md',
primaryGate: {
schema: 'qinglong/legacy-shadow-primary-gate-reference@v1',
origin: 'manual',
receiptFile: 'manual-primary-gate.json',
receiptSha256: 'a'.repeat(64),
},
rollout: {
defaultMode: 'off',
origins: { manual: 'primary' },
@@ -120,7 +126,7 @@ test('parses a time-bounded, manual-only rollout manifest', () => {
);
const disabled = parseRuntimeRolloutManifest(
{ schemaVersion: 1, revision: 'disabled-1', enabled: false },
{ schemaVersion: 2, revision: 'disabled-1', enabled: false },
NOW,
);
assert.equal(disabled.policy.modeFor('manual'), 'off');
@@ -128,6 +134,7 @@ test('parses a time-bounded, manual-only rollout manifest', () => {
test('rejects broad, stale, incomplete, and extensible rollout manifests', () => {
const cases = [
enabledManifest({ schemaVersion: 1 }),
enabledManifest({
rollout: {
defaultMode: 'primary',
@@ -135,6 +142,14 @@ test('rejects broad, stale, incomplete, and extensible rollout manifests', () =>
allowLegacyFallbackBeforeStart: false,
},
}),
enabledManifest({
primaryGate: {
schema: 'qinglong/legacy-shadow-primary-gate-reference@v1',
origin: 'manual',
receiptFile: '../escaped.json',
receiptSha256: 'a'.repeat(64),
},
}),
enabledManifest({
rollout: {
defaultMode: 'off',
+138 -3
View File
@@ -1,6 +1,7 @@
require('ts-node/register/transpile-only');
const assert = require('node:assert/strict');
const crypto = require('node:crypto');
const fs = require('node:fs/promises');
const os = require('node:os');
const path = require('node:path');
@@ -8,6 +9,9 @@ const { afterEach, test } = require('node:test');
const {
loadRuntimeRolloutManifest,
} = require('../../back/runtime/adapters/fs/runtimeRolloutManifestLoader');
const {
createLegacyShadowPrimaryGateReceipt,
} = require('../../back/runtime/domain/legacyShadowPrimaryGate');
const NOW = 1_750_000_000_000;
const directories = [];
@@ -18,15 +22,103 @@ async function fixturePath(name = 'qinglong3-rollout.json') {
return path.join(directory, name);
}
function enabledManifest() {
return {
function gateReceipt() {
const start = NOW - 20_000;
const end = NOW - 10_000;
const startup = {
schema: 'qinglong/legacy-shadow-startup-difference-report@v1',
profile: 'edge',
assessment: 'converged',
configuredOriginCount: 1,
coverage: { remaining: false },
byOrigin: [{ origin: 'manual' }],
};
const capture = {
schema: 'qinglong/legacy-shadow-capture-evidence@v1',
profile: 'edge',
startup,
capture: {
schema: 'qinglong/legacy-shadow-capture-report@v1',
profile: 'edge',
assessment: 'captured',
configuredOriginCount: 1,
window: {
basis: 'process_local_legacy_admission',
startInclusiveMs: start,
endExclusiveMs: end,
},
totals: { admitted: 8, captured: 8, failed: 0, pending: 0 },
byOrigin: [{ origin: 'manual' }],
capturePermille: 1_000,
},
qualification: { passed: true },
};
const terminal = {
schema: 'qinglong/legacy-shadow-terminal-difference-report@v1',
profile: 'edge',
observedAtMs: NOW - 3_000,
window: { startInclusiveMs: start, endExclusiveMs: end, closed: true },
coverage: {
direction: 'shadow_to_legacy',
cohort: 'legacy_owned_shadow_runs',
legacyWithoutShadow: 'not_measured',
},
assessment: 'matched',
scanned: 8,
remaining: false,
evidenceComplete: true,
counts: { matched: 8 },
byOrigin: [{ origin: 'manual', scanned: 8 }],
terminalAgreementPermille: 1_000,
fullyComparablePermille: 1_000,
};
const resource = {
schemaVersion: 1,
fixture: 'qinglong/legacy-shadow-resource-rollback-evidence@v1',
profile: 'edge',
workload: { mode: 'full', runtime: 'compiled_backend' },
rollback: {
performed: true,
legacyContinued: true,
shadowWritesStopped: true,
databaseIntegrity: 'ok',
},
qualification: { passed: true, violations: [] },
};
return createLegacyShadowPrimaryGateReceipt({
profile: 'edge',
generatedAtMs: NOW - 2_000,
capture,
terminal,
resource,
});
}
async function writeGateReceipt(sourcePath, value = gateReceipt()) {
const bytes = Buffer.from(`${JSON.stringify(value)}\n`);
await fs.writeFile(
path.join(path.dirname(sourcePath), 'primary-gate.json'),
bytes,
{ mode: 0o600 },
);
return crypto.createHash('sha256').update(bytes).digest('hex');
}
function enabledManifest(receiptSha256) {
return {
schemaVersion: 2,
revision: 'manual-primary-canary-1',
enabled: true,
approvedBy: 'operator:admin',
approvedAtMs: NOW - 1_000,
expiresAtMs: NOW + 60_000,
rollbackPlanRef: 'docs/runbooks/disable-primary.md',
primaryGate: {
schema: 'qinglong/legacy-shadow-primary-gate-reference@v1',
origin: 'manual',
receiptFile: 'primary-gate.json',
receiptSha256,
},
rollout: {
defaultMode: 'off',
origins: { manual: 'primary' },
@@ -69,7 +161,8 @@ test('fails closed when the rollout file is absent', async () => {
test('loads an approved manifest and audits only bounded metadata', async () => {
const sourcePath = await fixturePath();
const raw = JSON.stringify(enabledManifest());
const receiptSha256 = await writeGateReceipt(sourcePath);
const raw = JSON.stringify(enabledManifest(receiptSha256));
await fs.writeFile(sourcePath, raw);
const result = await loadRuntimeRolloutManifest(sourcePath, {
@@ -79,10 +172,52 @@ test('loads an approved manifest and audits only bounded metadata', async () =>
assert.equal(result.status, 'accepted');
assert.equal(result.policy.modeFor('manual'), 'primary');
assert.equal(result.audit.revision, 'manual-primary-canary-1');
assert.equal(result.primaryGateReceipt.assessment, 'eligible');
assert.match(result.audit.sourceSha256, /^[a-f0-9]{64}$/);
assert.doesNotMatch(JSON.stringify(result.audit), /operator:admin|rollback/);
});
test('rejects a missing, tampered or ineligible Primary gate receipt', async () => {
const missingPath = await fixturePath('missing-gate-manifest.json');
await fs.writeFile(
missingPath,
JSON.stringify(enabledManifest('a'.repeat(64))),
);
const missing = await loadRuntimeRolloutManifest(missingPath, {
clock: { now: () => NOW },
});
assert.equal(missing.status, 'rejected');
assert.equal(missing.audit.reasonCode, 'PRIMARY_GATE_READ_FAILED');
const tamperedPath = await fixturePath('tampered-gate-manifest.json');
const tampered = gateReceipt();
tampered.sources.terminal.counts.matched = 7;
const tamperedDigest = await writeGateReceipt(tamperedPath, tampered);
await fs.writeFile(
tamperedPath,
JSON.stringify(enabledManifest(tamperedDigest)),
);
const tamperedResult = await loadRuntimeRolloutManifest(tamperedPath, {
clock: { now: () => NOW },
});
assert.equal(tamperedResult.status, 'rejected');
assert.equal(tamperedResult.audit.reasonCode, 'PRIMARY_GATE_INVALID');
const invalidPath = await fixturePath('invalid-gate-manifest.json');
const ineligible = {
...gateReceipt(),
assessment: 'ineligible',
violations: ['terminal_not_matched'],
};
const digest = await writeGateReceipt(invalidPath, ineligible);
await fs.writeFile(invalidPath, JSON.stringify(enabledManifest(digest)));
const invalid = await loadRuntimeRolloutManifest(invalidPath, {
clock: { now: () => NOW },
});
assert.equal(invalid.status, 'rejected');
assert.equal(invalid.audit.reasonCode, 'PRIMARY_GATE_INVALID');
});
test('rejects malformed and oversized files without exposing their contents', async () => {
const malformedPath = await fixturePath('malformed.json');
await fs.writeFile(malformedPath, '{"approvedBy":"secret"');