fix(ci): gate Bandit and OSV Scanner jobs on detected security-relevant changes - #300
Conversation
…nt changes The detect-changes job (dorny/paths-filter) published a security_files output that no downstream job consumed, so every run paid for the Detect Security Changes job while python-security and osv-scanner ran unconditionally on nothing but the input toggle. Wire needs.detect-changes.outputs.security_files into both jobs' if: conditions, ANDed with the existing run-bandit/run-osv gates so current opt-outs keep working. The skip applies only on pull_request events: paths-filter has no diff base on schedule, push, or workflow_dispatch, so treating those as change-detected via github.event_name != 'pull_request' keeps Bandit and OSV Scanner running unconditionally outside pull_request, exactly as before. OSV Scanner in particular must never be skipped on schedule: it resolves a frozen lockfile against a live CVE feed, so its result can change with zero commits in the repo. The scheduled run is the entire point of scheduling it. security-gate already treats a skipped dependency as passing via its is_acceptable() helper (checks for success or skipped), so no gate change was needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe workflow now restricts security path filtering to pull requests. Bandit and OSV Scanner run on schedule, push, and manual events when their inputs enable them. ChangesSecurity workflow event gating
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to Bandit and OSV scans now skip pull requests without security-relevant changes while continuing to run when enabled on push, scheduled, and manual workflows. The change is ready to merge. Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
There was a problem hiding this comment.
🟢 Approval recommended
The gating logic is sound and preserves non-PR execution, with only minor documentation/comment accuracy tweaks suggested.
Pull request overview
This PR updates the org reusable GitHub Actions workflow to skip the Bandit and OSV Scanner jobs on pull requests that do not touch security-relevant files, using the existing detect-changes (dorny/paths-filter) job output.
Changes:
- Gate
python-security(Bandit) oninputs.run-banditandneeds.detect-changes.outputs.security_filesforpull_requestevents. - Gate
osv-scanneroninputs.run-osvandneeds.detect-changes.outputs.security_filesforpull_requestevents. - Add inline rationale and verification notes above both modified
if:conditions.
File summaries
| File | Description |
|---|---|
| .github/workflows/python-security-analysis.yml | Uses detect-changes output to skip Bandit and OSV Scanner on non-security PRs while preserving non-PR behavior. |
Review details
Suppressed comments (1)
.github/workflows/python-security-analysis.yml:307
- The #ASSUME note claims dorny/paths-filter has no diff base on schedule/push/workflow_dispatch. paths-filter can compute changes on these events (with different base semantics), so the comment is misleading. It would be clearer to document that we only use the paths-filter output to skip on pull_request, and force this job to run on all other events to avoid accidentally suppressing scheduled CVE scans.
# #ASSUME paths-filter has no diff base on schedule, push, or
# workflow_dispatch, so needs.detect-changes.outputs.security_files will
# not reliably be 'true' on those events. The `github.event_name !=
# 'pull_request'` clause short-circuits the OR to true there, so this job
# always runs outside pull_request regardless of the filter output. The
- Files reviewed: 1/1 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| # #ASSUME paths-filter has no diff base on schedule, push, or | ||
| # workflow_dispatch, so needs.detect-changes.outputs.security_files will | ||
| # not reliably be 'true' on those events. The `github.event_name != | ||
| # 'pull_request'` clause short-circuits the OR to true there, so the job | ||
| # always runs outside pull_request regardless of the filter output. |
| # #VERIFY run `gh api repos/ByronWilliamsCPA/.github/actions/workflows` and | ||
| # inspect a recent scheduled run of this workflow to confirm python-security | ||
| # shows result "success" (not "skipped") even though no PR diff exists. |



Summary
Fixes a dead-code defect in the
python-security-analysis.ymlreusable workflow: thedetect-changesjob (dorny/paths-filter) published asecurity_filesoutput that nothing consumed. Every run paid for the extraDetect Security Changesjob while the two expensive downstream jobs (Python SAST (Bandit),OSV Vulnerability Scanner) ran unconditionally on nothing but their input toggles.Fix
Wired
needs.detect-changes.outputs.security_filesinto both jobs'if:conditions, ANDed with the existingrun-bandit/run-osvinput gates:Why the pull_request restriction
dorny/paths-filterhas no diff base onschedule,push, orworkflow_dispatch, so its output will not reliably be'true'on those events. Thegithub.event_name != 'pull_request'clause short-circuits the||totrueon every non-pull_request event, so both jobs keep running exactly as they do today outside pull_request. The change-based skip applies ONLY to pull_request events.This distinction matters most for OSV Scanner: it is LIVE-STATE-DEPENDENT, not commit-determined. It resolves a frozen lockfile against a continuously updated CVE feed, so its result can change with zero commits in the repo. Its scheduled run is the entire point of scheduling it; a lockfile clean last week can be vulnerable today. Bandit, by contrast, is commit-determined (a pure function of the source at that commit), so skipping it on an unchanged-tree pull_request is safe.
Three-scenario walkthrough
github.event_name != 'pull_request'isfalse.security_filesdoes not match doc-only changes, so it is not'true'; the||evaluatesfalse.inputs.run-bandit/run-osv && false=false-> both jobs skip..pyfile:github.event_name != 'pull_request'isfalse, butsecurity_files == 'true'(the filter includes**/*.py); the||evaluatestrue.inputs.enabled && true=true-> both jobs run.github.event_name != 'pull_request'istrue, short-circuiting the||totrueregardless of the (unreliable, no-diff-base) filter output.inputs.enabled && true=true-> both jobs run, exactly as before.Explicit parentheses are used throughout so the intended
A && (B || C)grouping is unambiguous regardless of GitHub Actions' native&&/||precedence.Security-gate skip handling
Checked whether
security-gate(needs: [detect-changes, python-security, osv-scanner],if: always()) would read a newly-skipped dependency as a failure. Its validation step already handles this correctly:Verdict: no change needed.
is_acceptablealready treats"skipped"as passing alongside"success", so a job newly skipped by this change reads as a pass, not a failure.RAD tags
Added
#CRITICAL/#ASSUME/#EDGE/#VERIFYcomment blocks above both modifiedif:lines explaining the pull_request-only restriction and, for OSV specifically, why it must never be skipped on schedule.What was NOT touched
name:value changed (these are required status check contexts in org rulesets).detect-changesjob and its paths-filter step are unchanged; the existing filter list (including.github/workflows/**) is untouched.Rollout note
Consumer repos are SHA-pinned to this reusable workflow. This change reaches a repo only when that repo's Renovate/manual pin bump picks up the new commit; it cannot silently regress any consumer until they re-pin.
Verification
actionlint .github/workflows/python-security-analysis.yml: no new findings introduced (only pre-existing, unrelated shellcheck info/style notices on unmodifiedrun:blocks elsewhere in the file, confirmed identical onorigin/main).pre-commit run --all-files: all hooks passed.Generated with Claude Code
Summary by CodeRabbit