Files
stack/scripts/gate-history.test.mjs
T
2026-07-31 21:35:29 -05:00

325 lines
12 KiB
JavaScript

import assert from 'node:assert/strict';
import { mkdir, rm, writeFile } from 'node:fs/promises';
import path from 'node:path';
import { spawn, spawnSync } from 'node:child_process';
import test from 'node:test';
import {
assessProviderEvidence,
listProspectiveCommits,
readManifestAtCommit,
replayCommit,
verifyHistory,
} from './gate-history.mjs';
const fixtureRoot = path.join(process.cwd(), '.mosaic-test-work', `gate-history-${process.pid}`);
function git(root, ...args) {
const result = spawnSync('git', args, { cwd: root, encoding: 'utf8' });
assert.equal(result.status, 0, result.stderr);
return result.stdout.trim();
}
async function commitManifest(root, marker) {
await mkdir(path.join(root, 'gates'), { recursive: true });
await writeFile(
path.join(root, 'gates', 'gates.manifest.json'),
`${JSON.stringify({ schemaVersion: 1, marker })}\n`,
);
git(root, 'add', '.');
git(root, 'commit', '-m', marker);
return git(root, 'rev-parse', 'HEAD');
}
test.after(async () => {
await rm(fixtureRoot, { recursive: true, force: true });
});
test('prospective history reads each commit own manifest rather than the current tree', async () => {
await rm(fixtureRoot, { recursive: true, force: true });
await mkdir(fixtureRoot, { recursive: true });
git(fixtureRoot, 'init', '-q');
git(fixtureRoot, 'config', 'user.name', 'gate-test');
git(fixtureRoot, 'config', 'user.email', '[email protected]');
await writeFile(path.join(fixtureRoot, 'activation.txt'), 'activation\n');
git(fixtureRoot, 'add', '.');
git(fixtureRoot, 'commit', '-m', 'activation');
const activation = git(fixtureRoot, 'rev-parse', 'HEAD');
const first = await commitManifest(fixtureRoot, 'FIRST');
const second = await commitManifest(fixtureRoot, 'SECOND');
assert.deepEqual(await listProspectiveCommits(fixtureRoot, activation, second), [first, second]);
assert.equal((await readManifestAtCommit(fixtureRoot, first)).marker, 'FIRST');
assert.equal((await readManifestAtCommit(fixtureRoot, second)).marker, 'SECOND');
});
test('historical replay executes each selected commit verifier from that commit tree', async () => {
const root = `${fixtureRoot}-replay`;
await rm(root, { recursive: true, force: true });
await mkdir(path.join(root, 'scripts'), { recursive: true });
await mkdir(path.join(root, 'gates'), { recursive: true });
git(root, 'init', '-q');
git(root, 'config', 'user.name', 'gate-test');
git(root, 'config', 'user.email', '[email protected]');
await writeFile(path.join(root, 'gates', 'gates.manifest.json'), '{"schemaVersion":1}\n');
await writeFile(
path.join(root, 'scripts', 'gate-verify.mjs'),
"process.stderr.write('OLD TREE INERT\\n'); process.exitCode = 1;\n",
);
git(root, 'add', '.');
git(root, 'commit', '-m', 'inert historical verifier');
const inert = git(root, 'rev-parse', 'HEAD');
await writeFile(
path.join(root, 'scripts', 'gate-verify.mjs'),
"process.stdout.write('NEW TREE VERIFIED\\n');\n",
);
git(root, 'add', '.');
git(root, 'commit', '-m', 'fixed historical verifier');
const fixed = git(root, 'rev-parse', 'HEAD');
const inertResult = await replayCommit(root, inert);
const fixedResult = await replayCommit(root, fixed);
assert.notEqual(inertResult.status, 0);
assert.match(inertResult.stderr, /OLD TREE INERT/);
assert.equal(fixedResult.status, 0);
assert.match(fixedResult.stdout, /NEW TREE VERIFIED/);
});
test('historical install lifecycle cannot replace an authoritative verifier', async () => {
const root = `${fixtureRoot}-install-tamper`;
await rm(root, { recursive: true, force: true });
await mkdir(path.join(root, 'scripts'), { recursive: true });
await mkdir(path.join(root, 'gates'), { recursive: true });
git(root, 'init', '-q');
git(root, 'config', 'user.name', 'gate-test');
git(root, 'config', 'user.email', '[email protected]');
await writeFile(path.join(root, 'gates', 'gates.manifest.json'), '{"schemaVersion":1}\n');
await writeFile(
path.join(root, 'scripts', 'gate-verify.mjs'),
"process.stderr.write('ORIGINAL VERIFIER RAN\\n'); process.exitCode = 7;\n",
);
await writeFile(path.join(root, 'forged.mjs'), "process.stdout.write('FORGED SUCCESS\\n');\n");
await writeFile(
path.join(root, 'package.json'),
`${JSON.stringify({
name: 'historical-install-tamper',
version: '1.0.0',
scripts: { postinstall: 'cp forged.mjs scripts/gate-verify.mjs' },
})}\n`,
);
await writeFile(
path.join(root, 'pnpm-lock.yaml'),
"lockfileVersion: '9.0'\nsettings:\n autoInstallPeers: true\n excludeLinksFromLockfile: false\nimporters:\n .: {}\n",
);
git(root, 'add', '.');
git(root, 'commit', '-m', 'tampering lifecycle fixture');
const commit = git(root, 'rev-parse', 'HEAD');
const result = await replayCommit(root, commit);
assert.notEqual(result.status, 0);
assert.match(result.stderr, /authoritative archived file changed.*scripts\/gate-verify\.mjs/i);
assert.doesNotMatch(result.stdout, /FORGED SUCCESS/);
});
test('historical verifier receives no current-process secret environment', async () => {
const root = `${fixtureRoot}-secretless`;
await rm(root, { recursive: true, force: true });
await mkdir(path.join(root, 'scripts'), { recursive: true });
await mkdir(path.join(root, 'gates'), { recursive: true });
git(root, 'init', '-q');
git(root, 'config', 'user.name', 'gate-test');
git(root, 'config', 'user.email', '[email protected]');
await writeFile(path.join(root, 'gates', 'gates.manifest.json'), '{"schemaVersion":1}\n');
await writeFile(
path.join(root, 'scripts', 'gate-verify.mjs'),
"if (process.env.REPLAY_SENTINEL) { process.stderr.write('SECRET LEAKED\\n'); process.exitCode = 9; } else { process.stdout.write('SECRETLESS\\n'); }\n",
);
git(root, 'add', '.');
git(root, 'commit', '-m', 'secretless replay fixture');
const commit = git(root, 'rev-parse', 'HEAD');
process.env.REPLAY_SENTINEL = 'must-not-cross-boundary';
try {
const result = await replayCommit(root, commit);
assert.equal(result.status, 0, result.stderr);
assert.match(result.stdout, /SECRETLESS/);
assert.doesNotMatch(
`${result.stdout}${result.stderr}`,
/SECRET LEAKED|must-not-cross-boundary/,
);
} finally {
delete process.env.REPLAY_SENTINEL;
}
});
test('historical replay cannot observe a sibling process in the runner PID namespace', async () => {
const root = `${fixtureRoot}-pidless`;
await rm(root, { recursive: true, force: true });
await mkdir(path.join(root, 'scripts'), { recursive: true });
await mkdir(path.join(root, 'gates'), { recursive: true });
git(root, 'init', '-q');
git(root, 'config', 'user.name', 'gate-test');
git(root, 'config', 'user.email', '[email protected]');
await writeFile(path.join(root, 'gates', 'gates.manifest.json'), '{"schemaVersion":1}\n');
const sleeper = spawn('sleep', ['30'], {
env: { ...process.env, REPLAY_PID_SENTINEL: 'must-not-be-visible' },
});
try {
await writeFile(
path.join(root, 'scripts', 'gate-verify.mjs'),
`import { existsSync } from 'node:fs';\nif (existsSync('/proc/${sleeper.pid}/environ')) { process.stderr.write('HOST PID VISIBLE\\n'); process.exitCode = 9; } else { process.stdout.write('PIDLESS\\n'); }\n`,
);
git(root, 'add', '.');
git(root, 'commit', '-m', 'pid-isolated replay fixture');
const commit = git(root, 'rev-parse', 'HEAD');
const result = await replayCommit(root, commit);
assert.equal(result.status, 0, result.stderr);
assert.match(result.stdout, /PIDLESS/);
assert.doesNotMatch(`${result.stdout}${result.stderr}`, /HOST PID VISIBLE/);
} finally {
sleeper.kill('SIGTERM');
}
});
test('feature-branch history replays an inert intermediate commit before the healthy head', async () => {
const root = `${fixtureRoot}-feature`;
await rm(root, { recursive: true, force: true });
await mkdir(root, { recursive: true });
git(root, 'init', '-q');
git(root, 'config', 'user.name', 'gate-test');
git(root, 'config', 'user.email', '[email protected]');
await writeFile(path.join(root, 'activation.txt'), 'activation\n');
git(root, 'add', '.');
git(root, 'commit', '-m', 'activation');
const activation = git(root, 'rev-parse', 'HEAD');
git(root, 'update-ref', 'refs/remotes/origin/main', activation);
await mkdir(path.join(root, 'scripts'), { recursive: true });
await mkdir(path.join(root, 'gates'), { recursive: true });
await writeFile(path.join(root, 'gates', 'gates.manifest.json'), '{"schemaVersion":1}\n');
await writeFile(
path.join(root, 'scripts', 'gate-verify.mjs'),
"process.stderr.write('INTERMEDIATE INERT\\n'); process.exitCode = 1;\n",
);
git(root, 'add', '.');
git(root, 'commit', '-m', 'inert intermediate');
await writeFile(
path.join(root, 'scripts', 'gate-verify.mjs'),
"process.stdout.write('HEAD HEALTHY\\n');\n",
);
git(root, 'add', '.');
git(root, 'commit', '-m', 'healthy head');
const previousBranch = process.env.CI_COMMIT_BRANCH;
process.env.CI_COMMIT_BRANCH = 'feature/rm-02';
try {
const result = await verifyHistory({
root,
manifest: { schemaVersion: 1, activationCommit: activation },
});
assert.ok(result.failures.some((failure) => /INTERMEDIATE INERT/.test(failure)));
} finally {
if (previousBranch === undefined) delete process.env.CI_COMMIT_BRANCH;
else process.env.CI_COMMIT_BRANCH = previousBranch;
}
});
test('provider evidence distinguishes retained success, failure, and absent history', () => {
const pipelines = [
{
commit: 'aaa',
number: 1,
status: 'success',
steps: [{ name: 'gate-verify', status: 'success' }],
},
{
commit: 'bbb',
number: 2,
status: 'failure',
steps: [{ name: 'gate-verify', status: 'failure' }],
},
];
assert.deepEqual(assessProviderEvidence('aaa', pipelines), {
state: 'terminal-success',
detail: 'pipeline and gate-verify step succeeded',
});
assert.equal(assessProviderEvidence('bbb', pipelines).state, 'terminal-failure');
assert.equal(assessProviderEvidence('ccc', pipelines).state, 'absent');
});
test('duplicate gate-verify steps cannot establish provider success', () => {
const result = assessProviderEvidence('aaa', [
{
commit: 'aaa',
number: 7,
status: 'success',
steps: [
{ name: 'gate-verify', status: 'success' },
{ name: 'gate-verify', status: 'failure' },
],
},
]);
assert.equal(result.state, 'terminal-failure');
assert.match(result.detail, /ambiguous.*gate-verify/i);
});
test('a malformed single provider record cannot establish success', () => {
assert.equal(
assessProviderEvidence('aaa', [
{ commit: 'aaa', status: 'success', steps: [{ name: 'gate-verify', status: 'success' }] },
]).state,
'terminal-failure',
);
assert.equal(
assessProviderEvidence('bbb', [
{
commit: 'bbb',
number: 1,
status: 'surprising',
steps: [{ name: 'gate-verify', status: 'success' }],
},
]).state,
'terminal-failure',
);
});
test('provider evidence selects the highest numbered rerun deterministically', () => {
const failedThenSucceeded = [
{
commit: 'aaa',
number: 10,
status: 'failure',
steps: [{ name: 'gate-verify', status: 'failure' }],
},
{
commit: 'aaa',
number: 11,
status: 'success',
steps: [{ name: 'gate-verify', status: 'success' }],
},
];
const succeededThenFailed = [
{
commit: 'bbb',
number: 21,
status: 'success',
steps: [{ name: 'gate-verify', status: 'success' }],
},
{
commit: 'bbb',
number: 22,
status: 'failure',
steps: [{ name: 'gate-verify', status: 'failure' }],
},
];
assert.equal(assessProviderEvidence('aaa', failedThenSucceeded).state, 'terminal-success');
assert.equal(assessProviderEvidence('bbb', succeededThenFailed).state, 'terminal-failure');
assert.equal(
assessProviderEvidence('ccc', [
{ commit: 'ccc', status: 'success', steps: [{ name: 'gate-verify', status: 'success' }] },
{ commit: 'ccc', status: 'failure', steps: [{ name: 'gate-verify', status: 'failure' }] },
]).state,
'terminal-failure',
);
});