fix(security-evidence): decide from the lane's declared verdict, not its log - #2548
Conversation
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1351f780ee
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Claude finished @kyle-sexton's task in 5m 40s —— View job Code review —
|
|
Claude has reviewed this PR 3 times. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
…its log The guard inferred a verdict the lane had already computed, through two channels that were both wrong in the same way. It downloaded the lane's job log and grepped it. The lane's `Report review outcome` step is an inline github-script whose source is echoed into that same log and contains the skip phrases as string literals, so the grep matched every successful in-scope pull request and reddened exactly the ones the guard exists to approve (#2517). Anchoring to runner annotation lines removed the false positive but left the guard coupled to log text nothing upstream pins. It also re-derived the PR's security scope in its own Python fnmatch implementation while the lane matched with git check-ignore — two matchers that disagree on the patterns that distinguish them, and where the set -e scope-verdict defect lived. Both are replaced by the lane's declared outputs (ci-workflows#461). An absent verdict now fails CLOSED unless the head demonstrably moved, which is the one legitimate cause and is positively identified rather than assumed. An external failure still defers: the lane rules that green on purpose, and overturning it is a separate decision. The self-tests now EXECUTE the guard against environment fixtures instead of re-implementing its regexes and asserting on the copies — the shape that let them agree with a guard that was failing every pull request. They also run in CI now, in the guard's own job, where they ran nowhere before. Closes #2541 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeEvWwrK8KdQTFb5n9CrUP
…verdict cause A `!` / `?` / `+` pattern in the paths file hard-errors the lane's relevance step, which takes `relevant` down with it; the lane then fails open and reviews anyway, so a superseded head on top of that arrives here as an absent verdict. Same exit — the guard cannot see a verdict either way — but the message named only the stale pin, which would send a reader to the wrong place. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeEvWwrK8KdQTFb5n9CrUP
The declared outputs the guard now reads land in this release. The guard fails closed when they are absent at an unmoved head, so this pin and the guard change ship together — a re-pin backwards past v0.14.2 turns the lane red rather than quietly blind. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeEvWwrK8KdQTFb5n9CrUP
1351f78 to
645b9fe
Compare
comment-hygiene rejects an `owner/repo#N` tracker reference in a comment, and the release is the more useful pointer anyway: a reader checking whether their pin carries the declared outputs needs a version, not an issue number. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeEvWwrK8KdQTFb5n9CrUP
|
Claude finished @kyle-sexton's task in 3m 34s —— View job Code review —
|
…ller too The guard now names ci-workflows v0.14.2 in both its header and its production error message; this comment still named a pull request, so the two halves of the same contract pointed a reader at different things. The version is the useful pointer either way — it is what a reader compares their pin against. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeEvWwrK8KdQTFb5n9CrUP
|
Claude finished @kyle-sexton's task in 3m 11s —— View job Code review —
|
Closes #2541
Summary
The security-evidence guard inferred a verdict the lane had already computed, through two channels that were wrong in the same way.
It downloaded the lane's job log and grepped it. The lane's
Report review outcomestep is an inlinegithub-scriptwhose SOURCE is echoed into that same log and contains the skip phrases as string literals, so the grep matched every successful in-scope pull request and reddened exactly the ones the guard exists to approve (#2517). Anchoring to##[warning]/##[error]lines removed the false positive but left the guard coupled to log text nothing upstream pins.It also re-derived the PR's security scope in its own Python
fnmatchimplementation while the lane matches withgit check-ignore— two matchers that disagree on exactly the patterns that distinguish them, and where theset -escope-verdict defect lived.Fix
Both channels are replaced by the lane's declared outputs (melodic-software/ci-workflows#461), passed in from
needs.security-review:skipped/cancelledsuccessrelevant: falsereview-ran: truereview-ran: false,review-failed: truereview-ran: false,review-failed: falseLANE_RESULTemptyThe guard is now coupled to the pin: it fails closed when the outputs are absent at an unmoved head, so re-pinning BACKWARDS past the release carrying them turns it red rather than quietly blind. The caller's pin is bumped in this PR for exactly that reason.
actions: readis gone with the log read;pull-requests: readcovers the one remaining API call.Verification
scripts/verify-security-review-evidence.sh.test.shrewritten to EXECUTE the guard against environment fixtures in anenv -ichild shell, instead of re-implementing its regexes inside the harness and asserting on the copies — the shape that let the tests agree with a guard that was failing every pull request. 20 cases, all pass locally, covering every row of the table above plus two static checks (no log read, no second paths matcher).shellcheck --rcfile .shellcheckrcclean on both scripts, including the deliberately-enabled SC2310: the absent-verdict classifier reports on stdout with exit reserved for faults, the same verdict/status split the scope check needed.Related