fix(GHA004,GHA006): establish need before reporting, and say what was accepted - #74
Merged
Merged
Conversation
Both rules named their own exception in the finding they emitted, and neither checked whether it applied. GHA004 reported the pull_request_target trigger as Critical on its presence alone. The trigger is not a defect: it exists so a workflow can label a fork's pull request or post a comment, work pull_request cannot do because it has no token worth using. What makes it dangerous is executing the contributor's code in that context, which GHA007 already reports precisely. So the documented correct pattern scored the same Critical as a live remote-execution path, and a Critical nobody can act on is the one that teaches a reader to stop reading Criticals. - a job checks out the pull request's head -> Critical, as before - no job does -> Low, "confirm this boundary", since a later edit could add one The untrusted-checkout definition GHA007 carried privately moves to UntrustedPullRequestCheckout so both rules answer from one list and cannot drift. GHA007's behaviour is unchanged. GHA006 told a job to remove the credential it pushes with. Its remediation already said "unless a later step needs to push with the job token" while nothing established whether one did, so a release job running git push had a finding it could not close. It now stays quiet when a script after the checkout, in the same job, pushes. That signal is deliberately narrow, because suppressing this finding wrongly leaves a real credential exposure unreported: only git push in script text counts. Step names are not searched - "Set up git push credentials" would otherwise silence the finding - and a push in another job, or before the checkout, does not excuse it. 11 new tests, each quiet case paired with the neighbouring case that must still report. 309 pass across the solution. Neither this repository's workflows nor the repository that prompted the work change their results. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7HjzX5e8Wv7PKENDo2Uj7
Establishing need removed findings and left nothing in their place. A workflow
reported clean gave no way to tell "the rule examined this grant and accepted
it" from "the rule never looked", so the reasoning that made a finding
disappear was invisible to the person deciding whether to trust the result.
Acknowledgements carry that reasoning without becoming findings. They are a
separate list on the analysis result, because the client reads any finding as
Action required and counts it in the risk level - a correct workflow must not
be pushed into that state by the very check that approved it.
codeql.yml - Clean, 0 findings
Reviewed and accepted
security-events: write is required, not excessive GHA002 Line 8
'github/codeql-action/analyze' in job 'analyze' cannot work without it.
IWorkflowSecurityRule.Acknowledge is a defaulted interface member, so the seven
rules that never suppress anything needed no change and a test pins that their
default stays empty. GHA002 names the action that requires the grant; GHA006
names the job that pushes with the credential.
Five backend tests and one client test, each asserting both directions: what is
acknowledged is not also reported, and a file carrying an acknowledgement still
reads as Clean with zero findings.
314 backend tests and 28 frontend tests pass; both stacks build.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7HjzX5e8Wv7PKENDo2Uj7
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.
Follow-up to #73, in two parts: finish applying "establish need before reporting" to the rules that needed it, then make the result of that reasoning visible instead of silent.
Part 1 — two more rules named their own exception and ignored it
GHA004 —
pull_request_targetReported the trigger as Critical on its presence alone. But the trigger is not a defect: it exists so a workflow can label a fork's pull request or post a comment — work
pull_requestcannot do because it has no token worth using. What makes it dangerous is executing the contributor's code in that context, which GHA007 already reports precisely.So the documented-correct pattern scored the same Critical as a live remote-execution path. A Critical nobody can act on is the one that teaches a reader to stop reading Criticals.
The untrusted-checkout definition GHA007 carried privately moves into
UntrustedPullRequestCheckout, so both rules answer from one list and cannot drift. GHA007's behaviour is unchanged.GHA006 — persisted credentials
Told a job to remove the credential it pushes with. Its remediation already said "unless a later step needs to push with the job token" while nothing established whether one did, so a release job running
git pushhad a finding it could not close. It now stays quiet when a script after the checkout, in the same job, pushes.The signal is deliberately narrow, because wrongly suppressing this leaves a real credential exposure unreported. Only
git pushin script text counts — step names are not searched, since- name: Set up git push credentialswould otherwise silence a real finding. A push in another job, or before the checkout, does not excuse it.Part 2 — silence was the wrong answer
Establishing need removed findings and left nothing behind. A workflow reported clean gave no way to tell "the rule examined this grant and accepted it" from "the rule never looked".
Acknowledgements carry that reasoning without becoming findings, which matters concretely: the client reads any finding as
Action requiredand counts it toward the risk level, so shipping these as findings would push a correct workflow into the state the check just cleared it of.IWorkflowSecurityRule.Acknowledgeis a defaulted interface member, so the seven rules that never suppress anything needed no change — and a test pins that their default stays empty.Also audited, no change needed
GHA003already worked this way: it skips reusable-workflow-call jobs that cannot carrytimeout-minutes, and its comment notes the auto-fix would otherwise emit a broken patch. It was the model for both changes here.GHA001,GHA005,GHA007,GHA008,GHA009,GHA011have no equivalent "required" case — each reports something for which a safer alternative always exists.Verification
314 backend tests and 28 frontend tests pass; both stacks build. Every case that goes quiet is paired with the neighbouring case that must still report, and the acknowledgement tests assert both directions — what is acknowledged is never also reported, and a file carrying one still reads as Clean with zero findings.
Neither this repository's workflows nor the repository that prompted the work change their findings.
🤖 Generated with Claude Code
https://claude.ai/code/session_01N7HjzX5e8Wv7PKENDo2Uj7