Skip to content

GitHub Actions pinning#475

Open
lucperkins wants to merge 2 commits into
mainfrom
actions-pinning
Open

GitHub Actions pinning#475
lucperkins wants to merge 2 commits into
mainfrom
actions-pinning

Conversation

@lucperkins
Copy link
Copy Markdown
Member

@lucperkins lucperkins commented May 28, 2026

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

  • Chores
    • Enabled Flake support in the development environment
    • Pinned GitHub Actions and workflow dependencies to specific versions for enhanced security and reproducibility
    • Integrated Zizmor security scanning into automated CI/CD workflows
    • Enhanced dependency management configuration with improved scheduling and grouping strategies

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

📝 Walkthrough

Walkthrough

This PR hardens GitHub Actions security across build and CI workflows by pinning third-party actions to specific commits, applying least-privilege job-level permissions, standardizing system environment variables, and establishing automated policy enforcement through Dependabot and zizmor scanning for unpinned action references.

Changes

Workflow Security and Reliability Hardening

Layer / File(s) Summary
Development Environment Setup
.envrc
Enables flake-based development by adding use flake directive with shellcheck annotation.
Dependency Management and Security Policies
.github/dependabot.yml, .github/workflows/zizmor.yml, .github/zizmor.yml
Configures Dependabot to manage GitHub Actions updates with weekly schedule, cooldown, grouping, and ignore rules for DeterminateSystems/* actions. Adds zizmor security workflow that runs on pushes to main and pull requests with least-privilege permissions (security-events: write, contents: read, actions: read). Establishes zizmor rule requiring DeterminateSystems/* actions to use pinned refs.
Build Workflow Action Pinning and System Variables
.github/workflows/build.yml
Pins actions/checkout (v6.0.2) and actions/upload-artifact (v7.0.1) across build, build_static, test, vm_tests_all, flake_regressions, and manual jobs. Introduces SYSTEM environment variable derived from inputs.system in each job and updates Nix invocations (nix build, nix flake check) to consistently reference ${SYSTEM} instead of the workflow input directly.
CI Workflow Permission Hardening and Action Pinning
.github/workflows/ci.yml
Replaces top-level permissions with explicit job-level scopes: eval, build, and test jobs receive id-token and contents access; success job receives additional pull-requests, statuses, and deployments access. Pins actions/checkout to v6.0.2 and updates actions/download-artifact from v7 to v8.0.1 digest in success job. Sets persist-credentials: false for checkout steps across eval, success, and publish jobs.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A fluffy tale of actions pinned with care,
Permissions scoped, and secrets safe to share,
With zizmor's watchful eyes and Dependabot's might,
Our workflows shine more securely bright!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the primary change: pinning GitHub Actions to specific versions/commits across multiple workflow files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch actions-pinning

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 35cd98d and 44fc55e.

📒 Files selected for processing (6)
  • .envrc
  • .github/dependabot.yml
  • .github/workflows/build.yml
  • .github/workflows/ci.yml
  • .github/workflows/zizmor.yml
  • .github/zizmor.yml

Comment thread .github/workflows/ci.yml
Comment on lines +32 to 35
permissions:
id-token: write
contents: read
with:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 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:


🏁 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' || true

Repository: 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.

Suggested change
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant