ci: replace write-all with least-privilege permissions in orchestrator workflows#8569
Conversation
…r workflows
Resolves OpenSSF Scorecard Token-Permissions warnings on the orchestrator
workflows by removing the workflow-level write-all grant and declaring
the minimum scopes each stage requires.
Changes:
- ci-orchestrator.yml: replace `permissions: write-all` with workflow-level
`permissions: contents: read`. Add per-job `permissions:` blocks on every
stage caller (stage{1,2,3}-{seq,fast}) granting only the scopes each stage
needs.
- ci-orchestrator-stage1.yml: add `permissions: contents: read`.
- ci-orchestrator-stage2.yml: add `permissions: contents: read, checks: write`
(unit-test reporters).
- ci-orchestrator-stage3.yml: add `permissions: contents: read, packages: read,
security-events: write, actions: read` (CodeQL needs security-events:write;
docker/build/e2e jobs need packages:read and actions:read).
Permissions are declared in both the calling job and the called workflow.
Per GitHub's reusable-workflow rules, the effective permissions of a called
workflow are the intersection of (calling job's permissions) and (called
workflow's permissions), so both sides must grant a scope for it to apply.
Declaring on the called workflow also keeps it correct if invoked directly
by a different caller in the future.
Verified locally with `actionlint` (clean).
Fixes jaegertracing#8161
Signed-off-by: KrutikaPhirangi <138781661+KrutikaPhirangi@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR tightens GitHub Actions GITHUB_TOKEN permissions for the CI orchestrator and its reusable stage workflows to satisfy OpenSSF Scorecard’s Token-Permissions check and better follow least-privilege.
Changes:
- Replaces
permissions: write-allinci-orchestrator.ymlwith a minimal default (contents: read) and adds job-level permissions for stage callers. - Adds explicit top-level
permissions:blocks toci-orchestrator-stage{1,2,3}.ymlto ensure correct permissions when invoked directly. - Grants stage-specific scopes (e.g.,
checks: write,security-events: write,packages: read,actions: read) where required by downstream reusable workflows.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| .github/workflows/ci-orchestrator.yml | Drops workflow-wide write-all in favor of least-privilege and adds per-stage job permissions. |
| .github/workflows/ci-orchestrator-stage1.yml | Adds explicit stage-level permissions (contents: read). |
| .github/workflows/ci-orchestrator-stage2.yml | Adds stage-level permissions including checks: write for unit-test reporting. |
| .github/workflows/ci-orchestrator-stage3.yml | Adds stage-level permissions for CodeQL, Docker/E2E, and dependency review needs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- ci-orchestrator.yml: grant `actions: write` on the `summary` job; ci-summary-report.yml needs it for actions/cache save and `gh run download`, and the new workflow-level `contents: read` was stripping it via the reusable-workflow intersection. - ci-orchestrator-stage2.yml: drop workflow-level `checks: write`; declare it per-job on `unit-tests` only (ai-sidecar-gemini does not need it). - ci-orchestrator-stage3.yml: drop workflow-level `packages: read`, `security-events: write`, `actions: read`; declare them per-job on the only children that need them (docker-all-in-one → packages:read; codeql → security-events:write + actions:read). Other stage3 children remain at `contents: read`. Per-job scoping matches each leaf workflow's existing `permissions:` declarations. Signed-off-by: KrutikaPhirangi <138781661+KrutikaPhirangi@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8569 +/- ##
==========================================
+ Coverage 96.52% 96.53% +0.01%
==========================================
Files 330 330
Lines 17356 17356
==========================================
+ Hits 16753 16755 +2
+ Misses 454 453 -1
+ Partials 149 148 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Which problem is this PR solving?
Fixes #8161.
The OpenSSF Scorecard Token-Permissions check flags the orchestrator workflows because:
ci-orchestrator-stage1.yml,ci-orchestrator-stage2.yml,ci-orchestrator-stage3.yml— no top-levelpermissions:defined, so they inherit the default repository token scope.ci-orchestrator.yml— top-levelpermissions: write-all, granting theGITHUB_TOKENthe maximum set of privileges.Both violate the principle of least privilege.
Description of the changes
ci-orchestrator.yml— replaced workflow-levelpermissions: write-allwithpermissions: contents: read. Added per-jobpermissions:blocks on every stage caller (stage{1,2,3}-{seq,fast}) granting only the scopes that stage needs.ci-orchestrator-stage1.yml— addedpermissions: contents: read.ci-orchestrator-stage2.yml— addedpermissions: contents: readandchecks: write(for unit-test reporters).ci-orchestrator-stage3.yml— addedpermissions: contents: read,packages: read,security-events: write(CodeQL),actions: read(dependency-review / docker / e2e jobs).Why permissions are declared on both the calling job and the called workflow
Per GitHub's reusable-workflow permissions rules, the effective permissions of a called workflow are the intersection of (calling job's
permissions:) and (called workflow'spermissions:). Both sides must grant a scope for it to apply.Declaring on the called workflow as well keeps each stage correct if invoked directly by a different caller in the future, and gives a single point of truth for what each stage needs.
How was this change tested?
actionlintclean on all four files locally.security-events: write, docker/e2e →packages: read+actions: read, unit tests →checks: write).Checklist
actionlintclean