fix(test-policy): the workflow scan must read code, not comments - #191
Merged
Merged
Conversation
…policy The `no workflow invokes bare 'bun test'` policy scanned each workflow as raw lines, so a comment mentioning `bun test` was read as an invocation. That is wrong in both directions, and both were live in this repository at once: FALSE POSITIVE - release.yml's comment "`bun test` does not invoke tsc in this repository" has no --timeout because it is prose. The scan failed CI on both runners while the real command two lines below was the compliant `bun test --timeout 120000`. FALSE NEGATIVE - ci.yml's comment "`bun run test`, not bare `bun test`" matched, then took the `bun run test` early-exit and was waved through, so a comment counted as a compliant invocation and padded the positive control meant to prove the scan found real commands. The scan now parses the workflow and inspects only the executable content of `run:` steps, and strips shell comments inside those steps too, since a `#` line in a `run: |` block is prose as well. Stripping is quote-aware because the under-blocking direction is the dangerous one: a cut at the first `#` would drop the real invocation in `echo "a # b" && bun test`. A command carrying both forms is now judged on the bare one rather than excused by the other, which removes the exact mechanism behind the false negative. Measured while writing the fixtures: in a PLAIN scalar YAML itself ends the value at ` #`, so that shape carries no invocation for anything to hide - GitHub Actions would run `echo "a` and stop. Quote-awareness is load-bearing inside block scalars, and the fixture says so. Two-sided evidence on the real scan, not just on fixtures: with release.yml's command mutated to a bare `bun test` the policy test fails and names the command, and with the workflow unmutated - comment intact - it passes. Typecheck rc=0; suite 1135 pass, 56 skip, 0 fail, rc=0. Agent: Vespasian
Contributor
Author
|
[REVIEW] GO — #191 @ 1ba38c4 — lens: correctness+security+gates, reviewer unresolved-account002 (1 of 1) What I read:
Commands and measured results, all invoked unpiped:
Blocking P0/P1 findings: none. The change removes the demonstrated false-positive and false-negative paths caused by scanning YAML comments as executable commands, parses only YAML Non-blocking follow-ups: none. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The workflow scan reads prose as code, and it is wrong in BOTH directions
PR #189 landed the fallback — rewording a comment so the scan stops tripping on it. That unblocked CI and left the underlying defect in place. This lands the root-cause fix.
src/test-timeout-policy.tsread each workflow as raw lines, so a comment was judged as a command. Measured on currentmain:release.ymlbun test --timeout 120000ci.ymlbun run test— the real command, never seenci.ymlbun test --timeout 60000 …The false positive is the one that broke CI.
release.yml's explanatory comment has no--timeout, because it is prose.The false negative is the one nobody had noticed, and it is worse.
ci.yml's comment names bothbun run testandbun test. The scan matched it, hit thebun run testearly-continue, and waved it through as a compliant invocation — so it padded the positive control that exists to prove the scan finds real commands, while the actualrun: bun run testcommand stayed invisible to it. A control inflated by a comment is not a control.The fix
stripShellComments()andfindBunTestInvocations(): parse withBun.YAML.parse(native, typed in bun-types 1.3.14 — no new dependency), walk torun:values only, strip shell comments insiderun: |blocks quote-aware, and split commands on&&,||,;,|and newlines so a later--timeoutcannot excuse an earlier bare invocation. A command containing both forms is now judged on the bare one, which removes the early-exit that caused the false negative.Two-sided evidence, on the real scan rather than fixtures alone
run: bun test --timeout 120000torun: bun testfails withrelease.yml must use 'bun run test' or pass --timeout explicitly — got: bun test. Note the message now quotes a command; before the fix it quoted a comment.One fixture corrected by measurement rather than assumption: an under-blocking case (
echo "a # b" && bun test) initially failed, because in a plain YAML scalar YAML itself terminates the value at#— so no invocation exists to hide, and GitHub would run the truncatedecho "atoo. Quote-awareness is load-bearing only inside block scalars. The fixture and the comment now say so.Gates, run separately
bun run typecheck(tsc --noEmit) — rc=0bun run test— rc=0, 1135 pass / 56 skip / 0 fail across 74 filesStated plainly
No CI evidence yet.
ci.ymltriggers onpull_requestand push-to-mainonly, so the branch push ran nothing — opening this PR is what produces the first CI signal.Agent: Vespasian
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.