GitHub Actions pinning#475
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughPins and hardens GitHub workflows: action refs are pinned, job-level permissions are scoped, build jobs standardize a per-job SYSTEM env and disable checkout credentials, Dependabot configured for actions updates, zizmor workflow added with a rule enforcing pinned refs, and direnv flake enabled. ChangesWorkflow Security and Reliability Hardening
Sequence DiagramsequenceDiagram
participant Dev as Developer
participant GH as GitHub
participant Dependabot as Dependabot
participant Zizmor as zizmor-action
participant Build as build/ci workflows
Dev->>GH: push / pull_request triggers
GH->>Zizmor: run zizmor workflow (pinned action)
GH->>Build: run build/ci workflows (pinned actions, scoped permissions, SYSTEM env)
Dependabot->>GH: weekly actions update PRs
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/ci.yml:
- Around line 32-35: The caller workflow job build_x86_64-linux currently grants
only id-token: write and contents: read but passes publish_manual: true to the
reusable workflow; update the permissions block for build_x86_64-linux to also
grant pull-requests: write, statuses: write, and deployments: write (in addition
to id-token: write and contents: read) so the called workflow’s manual job can
perform the Netlify/manual updates using secrets.GITHUB_TOKEN; if you prefer,
gate these elevated permissions behind the same condition that sets
publish_manual to true so they are only granted when needed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f9b052b7-6f2b-4fce-a339-b38bc351e576
📒 Files selected for processing (6)
.envrc.github/dependabot.yml.github/workflows/build.yml.github/workflows/ci.yml.github/workflows/zizmor.yml.github/zizmor.yml
| permissions: | ||
| id-token: write | ||
| contents: read | ||
| with: |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In GitHub Actions reusable workflows, do permissions set on the caller job cap the GITHUB_TOKEN permissions available inside called workflow jobs, even if the called workflow asks for broader permissions?
💡 Result:
Yes, permissions set on a caller job explicitly cap the GITHUB_TOKEN permissions available to any jobs within a called reusable workflow [1][2]. When you call a reusable workflow, GitHub validates the permissions requested by the called workflow against the permissions granted by the caller job [3]. The following rules apply: 1. Mandatory Capping: The permissions available to a reusable workflow can only be maintained or reduced from those granted by the caller job; they cannot be elevated [4][1]. If the called workflow requests broader permissions than what is provided by the caller job, the workflow will fail validation before it even begins executing [2][3]. 2. Default Behavior: If you do not explicitly define permissions on the caller job, the called workflow inherits the default permissions for the GITHUB_TOKEN [1]. 3. Principle of Least Privilege: Because reusable workflows are treated similarly to actions in terms of permission scoping, it is considered a security best practice to grant the caller job only the minimum permissions required for the tasks performed by the called workflow [2][5]. If a called workflow requires specific permissions to function (e.g., contents: write), you must ensure that the caller job explicitly grants those permissions (or a broader superset) [2][3]. If the caller job fails to grant sufficient permissions, the workflow execution will be rejected by GitHub [3].
Citations:
- 1: https://github.com/github/docs/blob/main/content/actions/reference/workflows-and-actions/reusing-workflow-configurations.md
- 2: https://www.kenmuse.com/blog/github-actions-workflow-permissions/
- 3:
call-workflowgenerated caller jobs omit requiredpermissions:for reusable workflows github/gh-aw#21071 - 4: https://github.com/github/docs/blob/main/content/actions/how-tos/reuse-automations/reuse-workflows.md
- 5: https://github.com/github/docs/blob/main/content/actions/tutorials/authenticate-with-github_token.md
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Files =="
ls -la .github/workflows || true
echo
echo "== ci.yml (relevant sections) =="
# Show around reported lines and around build_x86_64-linux usage
sed -n '1,120p' .github/workflows/ci.yml | nl -ba | sed -n '20,80p' || true
rg -n "build_x86_64-linux|publish_manual|uses: \\.\/\\.github\\/workflows\\/build\\.yml|uses: \\.\\/\\.github\\/workflows\\/build\\.yml" .github/workflows/ci.yml || true
sed -n '1,220p' .github/workflows/ci.yml | nl -ba | sed -n '1,220p' || true
echo
echo "== build.yml (manual job + permissions) =="
rg -n "job[s]?:|manual:|publish_manual|permissions:" .github/workflows/build.yml || true
# Print around manual job section and around any publish_manual logic
python3 - <<'PY'
import re, itertools, pathlib
p = pathlib.Path(".github/workflows/build.yml")
text = p.read_text().splitlines()
# find lines with "manual:" and "permissions:"
hits = [i for i,l in enumerate(text) if re.search(r'^\s*manual:\s*$', l) or re.search(r'^\s*manual:\s*$', l)]
perm_hits = [i for i,l in enumerate(text) if re.search(r'^\s*permissions:\s*$', l)]
print("manual line indices:", hits)
print("permissions line indices:", perm_hits)
PY
# Best-effort contextual extracts (avoid huge output)
sed -n '1,260p' .github/workflows/build.yml | nl -ba | sed -n '1,260p' || trueRepository: DeterminateSystems/nix-src
Length of output: 1087
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== ci.yml: locate build_x86_64-linux and the uses: build.yml call =="
rg -n "build_x86_64-linux" .github/workflows/ci.yml || true
rg -n "uses:\s*\./\.github/workflows/build\.yml|publish_manual|permissions:" .github/workflows/ci.yml || true
echo
echo "== ci.yml: print around build_x86_64-linux usage (best-effort) =="
# Print entire file with line numbers via cat -n (file is small: 6086 bytes)
cat -n .github/workflows/ci.yml | sed -n '1,220p'
echo
echo "== build.yml: print around manual job and its permissions =="
cat -n .github/workflows/build.yml | sed -n '200,320p'
echo
echo "== build.yml: print around publish_manual input handling =="
rg -n "publish_manual" .github/workflows/build.yml || true
cat -n .github/workflows/build.yml | sed -n '1,120p'Repository: DeterminateSystems/nix-src
Length of output: 17052
Widen build_x86_64-linux permissions for the reusable workflow’s manual publish path.
In .github/workflows/ci.yml, build_x86_64-linux sets only permissions: id-token: write and contents: read but passes publish_manual: true to .github/workflows/build.yml. The called workflow’s manual job requires pull-requests, statuses, and deployments write permissions, and those permissions can’t be elevated beyond what the caller grants—so the Netlify/manual update path that uses secrets.GITHUB_TOKEN can fail.
Suggested fix
build_x86_64-linux:
uses: ./.github/workflows/build.yml
permissions:
id-token: write
contents: read
+ pull-requests: write
+ statuses: write
+ deployments: write
with:
system: x86_64-linux
runner: namespace-profile-linuxamd32c64g-cache
runner_for_virt: UbuntuLatest32Cores128G
runner_small: ubuntu-latest
run_tests: true
run_vm_tests: true
run_regression_tests: true
publish_manual: true📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| permissions: | |
| id-token: write | |
| contents: read | |
| with: | |
| permissions: | |
| id-token: write | |
| contents: read | |
| pull-requests: write | |
| statuses: write | |
| deployments: write | |
| with: |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/ci.yml around lines 32 - 35, The caller workflow job
build_x86_64-linux currently grants only id-token: write and contents: read but
passes publish_manual: true to the reusable workflow; update the permissions
block for build_x86_64-linux to also grant pull-requests: write, statuses:
write, and deployments: write (in addition to id-token: write and contents:
read) so the called workflow’s manual job can perform the Netlify/manual updates
using secrets.GITHUB_TOKEN; if you prefer, gate these elevated permissions
behind the same condition that sets publish_manual to true so they are only
granted when needed.
This PR updates our GitHub Actions setup to include pinned hashes for non-DetSys Actions, Zizmor checks, and a more granular Dependabot configuration.
Summary by CodeRabbit