Skip to content

fix(scan/parse): reject the explicit off-pin scan language on a pinned project (#667) - #750

Open
gadievron wants to merge 2 commits into
masterfrom
fix/667-scan-l-reject
Open

gadievron wants to merge 2 commits into
masterfrom
fix/667-scan-l-reject

Conversation

@gadievron

@gadievron gadievron commented Sep 26, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

openant scan -l <other> (and parse -l <other>) on a language-pinned project previously wrote the other language's scan into the pinned language's directory in place (#667). Per the maintainer's REJECT-now ruling, this PR rejects the explicit off-pin request at the CLI boundary, before any artifact/meta write or Python invocation.

The amendment (the wiring pin)

The original guard was tested at the helper level (TestRejectOffPinLanguage drives rejectOffPinLanguage directly). The wiring — the actual cobra call in runScan/runParse — was not: the E1/E2 class (a PR whose suite passes with the fix's production wiring removed).

This amendment adds two subprocess wiring tests:

Both tests fail when the guard's call site is removed (the wiring mutants, executed) — the E1 class is killed for both surfaces.

The C4 evidence (the M9-1 wiring clause)

Every prod hunk carries a prod-mutant receipt: the guard neutered (3 tests fail), the exemption inverted (3), the supported-set membership inverted (2), the scan wiring removed (1 — the wiring test), the parse wiring removed (1), the parse defaults wrong (1). Every mutant kills — the tests constrain the behavior.

The declared notes

  • Symlink bypass in the output-pin guard (DECLARED RESIDUAL, executed on this head): the guard's filepath.Abs comparison does not resolve symlinks, so a symlinked -o path pointing at the pin directory takes the exemption — the bypass was demonstrated by execution, not by inspection. Two honest notes from the refutation round: (a) the earlier "resolved via $PWD always" severity argument was false (Getwd honors $PWD; there is no demonstrated accidental-resolution path), so this is a deliberate-symlink attacker-side residual, not an accidental one; (b) the in-tree fix is not a naive filepath.EvalSymlinks swap — it errors on not-yet-created output dirs and would introduce false rejections; the in-tree model (internal/server/server.go:1935-1939) resolves both sides before comparing, and a deny-on-error fallback needs its own test. Symlinks stay declared out of scope for this PR; the guard-tightening is future work with that test attached.

  • The parse call-site's wiring is now pinned; the helper-level discrimination tests (the -o "" shape, the spelling cases) remain in the original suite.

  • The second commit is re-authored to the noreply identity; the first still carries a machine-local author address — declared, metadata-only (M9-5-exempt). Before confirming a squash merge, read the squash-message box and remove any machine-local Co-authored-by trailer.

Fixes #667. Cross-linked: #691 (init's missing validation — its message steers there).

Merge notes (added 2026-10-06)

…'s REJECT-now ruling) — the T1's 5 rounds: the parse surface guarded (F1), the supported-set message (F2), the EFFECTIVE-output exemption with the Abs-canonicalized pin-path compare (D1/D2/F-A, the -o-empty and tab-completion bypasses closed), the registry-failure fallthrough (D3), the exemption + spelling tests (D4/F-1)
…nd, the subprocess form driving the REAL runScan with a jailed HOME + a python-pinned active project + the flag Set() to mark the explicit form: the supported off-pin (go) gets #667, the unsupported (cobol) gets #691, the pin dir stays clean. The E1 class killed: the guard's WIRING is now tested, not just its helper.
@gadievron
gadievron force-pushed the fix/667-scan-l-reject branch from 96691b5 to a0a96ce Compare September 27, 2026 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant