fix(workflows): declare the permissions these jobs' actions actually need - #497
Conversation
…need
Three jobs run an action that needs a scope the job never declares. A consumer
cannot work around any of them: a called workflow may only REDUCE the caller's
permissions, never raise them, so granting the scope on the calling job has no
effect once the callee declares a narrower set.
**lint.yml / files-changed — `pull-requests: read`.** `dorny/paths-filter` does
not diff git for a `pull_request` event; it calls
`GET /repos/{owner}/{repo}/pulls/{number}/files`. The job declared no
`permissions` of its own, so it inherited the workflow-level `contents: read`
and the call came back `Resource not accessible by integration`. The job fails,
every lint job downstream is skipped, and `test-required-check` exits 1 — so the
whole check reports failure without a single linter having run.
**zizmor.yml / zizmor — `contents: read`.** The job declared only
`security-events: write`, so `actions/checkout` had no read scope. This is
invisible on a public repo, where the clone succeeds unauthenticated anyway. On
a private one git reports the repository as absent:
fatal: repository 'https://github.com/<owner>/<repo>/' not found
which reads as a wrong URL rather than a missing scope. `zizmor` then never
produces `results.sarif`, so the upload step fails too.
**set-default-labels.yml — `contents: read`.** Same shape as zizmor: declares
`issues: write` and checks out without a read scope. Found by sweeping the rest
of the directory for the same class rather than waiting for it to be reported.
Verified against the runner's own `GITHUB_TOKEN Permissions` block on a private
consumer, which showed `Contents: read, Metadata: read` for the lint job (the
caller's `pull-requests: read` silently dropped) and `Metadata: read,
SecurityEvents: write` for zizmor.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GogDZZtdAedQLUrW4cAzLb
|
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 (3)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe pull request adds explicit GitHub Actions read permissions. The lint workflow can read pull-request file lists. The label and zizmor workflows can check out private repositories. ChangesWorkflow permissions
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to The workflows now grant the read access needed to detect pull-request files and check out private repositories, restoring lint, labeling, and zizmor execution without introducing an outstanding merge-readiness risk. 🚥 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 |
## [23.0.5](v23.0.4...v23.0.5) (2026-09-05) ### Bug Fixes * **deps:** update github-actions ([#488](#488)) ([593b416](593b416)) * **deps:** update patch updates to ^8.10.1 ([#496](#496)) ([f0a80c6](f0a80c6)) * **workflows:** declare the permissions these jobs' actions actually need ([#497](#497)) ([c25805b](c25805b))
Three reusable-workflow jobs run an action that needs a scope the job never declares.
Consumers cannot work around any of these. A called workflow may only reduce the caller’s permissions, never raise them — so granting the scope on the calling job has no effect once the callee declares a narrower set.
lint.ymlfiles-changedpull-requests: readdorny/paths-filterzizmor.ymlzizmorcontents: readactions/checkoutset-default-labels.ymlset-default-labelscontents: readactions/checkoutlint.yml —
files-changeddorny/paths-filterdoes not diff git for apull_requestevent; it callsGET /repos/{owner}/{repo}/pulls/{number}/files. The job declared nopermissionsof its own, so it inherited the workflow-levelcontents: readand the call came back:The job fails, every lint job downstream is skipped, and
test-required-checkexits 1 — so the check reports failure without a single linter having run.zizmor.yml —
zizmorThe job declared only
security-events: write, soactions/checkouthad no read scope. This is invisible on a public repo, where the clone succeeds unauthenticated anyway. On a private one git reports the repository as absent:which reads as a wrong URL rather than a missing scope.
zizmorthen never producesresults.sarif, so the upload step fails too.set-default-labels.yml
Same shape as zizmor. Found by sweeping the rest of
.github/workflows/for the same class rather than waiting for it to be reported — it has not bitten yet because it is gated ongithub.repository == inputs.target-repo.Verification
Read off the runner’s own
GITHUB_TOKEN Permissionsblock on a private consumer, rather than inferred from the YAML:In the first, the caller had granted
pull-requests: readand it was silently dropped. After the change a re-run of the sweep reports every job declaring what its actions need, and all three files still parse.Each addition is strictly a widening, so no existing consumer loses anything.
🤖 Generated with Claude Code
https://claude.ai/code/session_01GogDZZtdAedQLUrW4cAzLb
Summary by CodeRabbit