fix(#1279): node-test prover fail-closes on missing violationFixture + honest projection docs
Addresses the #1314 maintainer review (trek-e): - Major 1 (fail-OPEN): defaultProveFailFirst's node-test branch only guarded `if (!fixture)`. A missing/typo'd/stale violationFixture made GSD_PROHIB_SUBJECT point at a missing file; an honest negative test threw ENOENT *inside its callback* (a failing test named distinctly from the file), which isNonVacuousNodeTestRed accepted as proof -> a green forged from a setup crash. Now requires fs.existsSync(path.resolve(cwd, fixture)) before spawning, symmetric with the lint-rule path's file-result guard. Regression test pins it (RED without the guard); a second test pins cwd-relative fixture resolution. - Major 2 (misleading prose): the #1278 projection carries no violationFixture, so the deterministic-locate path always hard-gates (fail-closed) until a check_violation_fixture scalar is threaded through. verify-phase.md and prohibition-probe.md no longer read as if the projected path produces greens; the ADR-550 addendum records both items. Tracked as follow-up #1346. - Documented residual: existence is necessary but not sufficient (a red caused by the env being set vs the subject's content); recorded as a constraint, in #1346. - Nit: stale 'NOT attested fail-first' comment -> 'NOT machine-proven fail-first'. 64 tests pass; eslint + tsc clean; changeset valid.
This commit is contained in:
@@ -539,7 +539,23 @@ function defaultProveFailFirst(check: CheckDescriptor, cwd: string, timeoutMs?:
|
||||
}
|
||||
if (check.kind === 'node-test') {
|
||||
const fixture = check.violationFixture;
|
||||
if (!fixture) return { provenFailFirst: false }; // no fixture -> hard-gate (NEVER attestation)
|
||||
// Fail-CLOSED on a missing/typo'd/stale fixture path, SYMMETRIC with the lint-rule path's
|
||||
// `eslintFileResultCount >= 1` guard. Without the existence check, a non-existent fixture makes
|
||||
// `GSD_PROHIB_SUBJECT` point at a missing file; an honest negative test reading that subject
|
||||
// throws ENOENT *inside its callback* — a failing test named DISTINCTLY from the file, which
|
||||
// `isNonVacuousNodeTestRed` would accept as proof. That is fail-OPEN: a typo forges a green from
|
||||
// a setup crash, not from the prohibition firing. Requiring the fixture to exist before spawning
|
||||
// closes the realistic typo/stale-path case (#1279 review, Major 1).
|
||||
//
|
||||
// KNOWN RESIDUAL (documented, fail-open direction, tracked follow-up #1346): existence is
|
||||
// necessary but not sufficient — a deliberately deceptive negative test that reds merely BECAUSE
|
||||
// `GSD_PROHIB_SUBJECT` is set (rather than because the subject's CONTENT violates the must-NOT)
|
||||
// is still accepted. Proving "the red was CAUSED BY the violation" cannot be done generically for
|
||||
// an arbitrary author-supplied test, so it is recorded as a constraint, not silently implied-solved.
|
||||
// Resolve the fixture against `cwd` (NOT the verify process's cwd): the spawned test reads
|
||||
// `GSD_PROHIB_SUBJECT` and resolves a relative subject against `cwd`, so the existence check must
|
||||
// use the SAME base or it could pass here yet ENOENT in the child (re-opening the fail-open hole).
|
||||
if (!fixture || !fs.existsSync(path.resolve(cwd, fixture))) return { provenFailFirst: false };
|
||||
let out = '';
|
||||
try {
|
||||
out = execFileSync(process.execPath, buildNodeTestArgs(check), {
|
||||
@@ -632,7 +648,7 @@ export function runProhibitionEnforcement(
|
||||
const passed = proof.provenFailFirst === true && run.passed === true;
|
||||
|
||||
if (!passed) {
|
||||
// NOT attested fail-first OR did not genuinely pass -> fail-closed, located: true (an actual
|
||||
// NOT machine-proven fail-first OR did not genuinely pass -> fail-closed, located: true (an actual
|
||||
// located miss/fail). Hard-gate applies in BOTH modes; the disposition stays non-green / flagged.
|
||||
const disposition = dispositionForProhibition(prohibition, { enforcementEvidence: [] });
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user