fix(quality): close registry silent-defeat paths
ci/woodpecker/pr/ci Pipeline was successful

This commit is contained in:
2026-08-01 11:28:28 -05:00
parent 83d2ecb224
commit 32b490a712
11 changed files with 889 additions and 52 deletions
+111 -1
View File
@@ -18,7 +18,6 @@ async function fixture(name = 'case') {
function baseManifest() {
return {
schemaVersion: 1,
activationCommit: null,
gateRoots: ['gates'],
governingClaimFiles: [],
coverageBoundary: { included: ['meta fixture'], excluded: [], trackedBy: 'RM-54' },
@@ -157,6 +156,117 @@ test('duplicate stable ids and unsupported schema versions are rejected', async
assert.match(output(result), /duplicate criterion id META-CRIT-1/i);
});
test('misspelled nested assertion fields are rejected instead of becoming optional', async () => {
const root = await fixture('nested-schema-typo');
await writeGate(root);
const manifest = baseManifest();
manifest.gates[0].cases[0].required.outputPatern = 'META_REJECT';
manifest.gates[0].cases[0].actual.outputPatern = 'META_REJECT';
await writeManifest(root, manifest);
const result = verify(root);
assert.notEqual(result.status, 0);
assert.match(output(result), /required.*unknown field outputPatern/i);
assert.match(output(result), /actual.*unknown field outputPatern/i);
});
test('present outcome patterns cannot be empty assertion bypasses', async () => {
const root = await fixture('nested-schema-empty-patterns');
await writeGate(root);
const manifest = baseManifest();
manifest.gates[0].cases[0].required.outputPattern = '';
manifest.gates[0].cases[0].actual.notOutputPattern = ' ';
await writeManifest(root, manifest);
const result = verify(root, ['--structure-only']);
assert.notEqual(result.status, 0);
assert.match(output(result), /required.outputPattern: expected a non-empty pattern/i);
assert.match(output(result), /actual.notOutputPattern: expected a non-empty pattern/i);
});
test('nested discriminator and comparison fields reject wrong types', async () => {
const root = await fixture('nested-schema-types');
await writeGate(root);
const manifest = baseManifest();
manifest.gates[0].cases[0].mustFail = 'true';
manifest.gates[0].cases[0].required.exitCode = '7';
manifest.gates[0].cases[0].actual.outputPattern = 7;
await writeManifest(root, manifest);
const result = verify(root, ['--structure-only']);
assert.notEqual(result.status, 0);
assert.match(output(result), /mustFail: expected a boolean/i);
assert.match(output(result), /required.exitCode: expected an integer/i);
assert.match(output(result), /actual.outputPattern: expected a string/i);
});
test('recursive closed-schema guards reject unknown fields in every nested assertion object', async () => {
const source = JSON.parse(
await readFile(path.join(process.cwd(), 'gates', 'gates.manifest.json'), 'utf8'),
);
const checkout = source.gates.find((gate) => gate.id === 'checkout-preflight');
const stale = checkout.cases.find((gateCase) => gateCase.id === 'stale-build-lock');
const queue = source.gates.find((gate) => gate.id === 'ci-queue-wait');
const queueCase = queue.cases.find((gateCase) => gateCase.id === 'terminal-success');
const targets = [
['coverageBoundary', (manifest) => manifest.coverageBoundary],
['mergeAssertions', (manifest) => manifest.mergeAssertions],
[
'meaningChanges',
(manifest) =>
manifest.criteria.find((criterion) => criterion.meaningChanges.length).meaningChanges[0],
],
['proseClaims', (manifest) => manifest.proseClaims[0]],
['compatibility expected', (manifest) => manifest.compatibilityScenarios[0].expected],
[
'deployment',
(manifest) => manifest.gates.find((gate) => gate.id === 'ci-queue-wait').deployment,
],
['inertMutation', (manifest) => manifest.gates[0].inertMutation],
['inert expected', (manifest) => manifest.gates[0].inertMutation.expected],
['required', (manifest) => manifest.gates[0].cases[0].required],
['actual', (manifest) => manifest.gates[0].cases[0].actual],
[
'fixture',
(manifest) =>
manifest.gates
.find((gate) => gate.id === 'checkout-preflight')
.cases.find((gateCase) => gateCase.id === 'stale-build-lock').fixture,
],
[
'write entry',
(manifest) =>
manifest.gates
.find((gate) => gate.id === 'checkout-preflight')
.cases.find((gateCase) => gateCase.id === 'stale-build-lock').fixture.writeFiles[0],
],
[
'replace entry',
(manifest) =>
manifest.gates
.find((gate) => gate.id === 'checkout-preflight')
.cases.find((gateCase) => gateCase.id === 'criterion-misbinding').fixture.replaceFiles[0],
],
[
'defect',
(manifest) =>
manifest.gates
.find((gate) => gate.id === 'ci-queue-wait')
.cases.find((gateCase) => gateCase.id === 'terminal-success').defect,
],
];
assert.ok(stale.fixture && queueCase.defect);
for (const [name, select] of targets) {
const root = await fixture(`recursive-${name.replaceAll(' ', '-')}`);
const manifest = structuredClone(source);
select(manifest).unexpectedNestedField = true;
await writeManifest(root, manifest);
const result = verify(root, ['--structure-only']);
assert.notEqual(result.status, 0, `${name}: ${output(result)}`);
assert.match(output(result), /unknown field unexpectedNestedField/i, name);
}
});
test('manifest-controlled fixture paths cannot escape the sandbox', async () => {
const root = await fixture('path-traversal');
await writeGate(root);