Repository navigation
security(ci): enforce SHA-pinned and allowlisted GitHub Actions - #562
Open
sulaimonifeoluwa4-blip wants to merge 1 commit into
Open
sulaimonifeoluwa4-blip wants to merge 1 commit into
sulaimonifeoluwa4-blip wants to merge 1 commit into
Conversation
…llowlist Tags such as actions/checkout@v4 and dtolnay/rust-toolchain@stable are mutable, so a compromised or retargeted upstream ref can run unreviewed code with the repository token. Pin every external action to a full-length commit SHA, record the reviewed pins in .github/actions-allowlist.json, and add a dependency-free checker plus CI workflow so an unpinned, unknown, or unused action fails review. Token permissions stay read-only and the checker rejects new write scopes. Closes Sub-Rosa-Issue#489 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
Collaborator
|
I reviewed the diff and did not find a malicious payload, but this branch now conflicts with current main after related changes landed. Please rebase on current main, preserve the already-merged security and CI gates, rerun the relevant tests, and update this PR; it is not safe to merge the stale conflict state. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #489.
Every external GitHub Action used by
.github/workflows/**is now referenced by a full-length commit SHA, recorded in a machine-readable allowlist, and verified by a blocking CI job plus tests. All workflows keeppermissions: contents: read; no token scope was added.Issue #489 expected the file-level pins from #481 to be merged first. Those pins are not on
main(all workflows still usedactions/checkout@v4,actions/setup-node@v4,pnpm/action-setup@v4,Swatinem/rust-cache@v2,dtolnay/rust-toolchain@stable), so this PR includes the pinning itself and then enforces it. The repository settings requested by the issue cannot be stored in git — the required settings and the final allowlist are documented indocs/CI.md, and the new check enforces the same rules at review time so the policy cannot drift between settings and files.Changes
.github/workflows/bindings-check.ymltoolchain: stable.github/workflows/contract.ymltoolchain: stable.github/workflows/coverage.yml.github/workflows/docs-links.yml.github/workflows/env-examples.yml.github/workflows/line-lengths.yml.github/workflows/web.yml.github/actions-allowlist.jsonscripts/check-actions-policy.mjsscripts/check-actions-policy.test.mjs.github/workflows/actions-policy.ymlpackage.jsonactions:checkandactions:testscript aliasesdocs/CI.mdNo dependencies, lockfile entries, lifecycle scripts, binaries, or secret references were added.
Final allowlist
Each SHA is exactly the commit the previously used mutable ref resolved to when this PR was prepared (
git ls-remote, 2026-10-23). No action code changes — only the reference stops being mutable.actions/checkout@v411d5960a326750d5838078e36cf38b85af677262v4.4.0actions/setup-node@v449933ea5288caeca8642d1e84afbd3f7d6820020v4.4.0pnpm/action-setup@v4b906affcce14559ad1aafd4ab0e942779e9f58b1v4.3.0dtolnay/rust-toolchain@stableb725eda525362e7cf34af9a7243cac1e3f01a7ecstablebranch headSwatinem/rust-cache@v2d1527c8f67ef9af357290475d4af4b0fab8f12e0v2.9.3dtolnay/rust-toolchaincaveat: the action derives the toolchain from the ref it is called with (@stable). Once that ref is a SHA, the toolchain name is gone, so both usages now passtoolchain: stableexplicitly. Behavior is unchanged.Enforcement added
scripts/check-actions-policy.mjs(no dependencies, runs on plain Node 22) fails when:@v4or@stableare rejected;.github/actions-allowlist.json(even when the SHA is valid);docker://action is used (cannot be pinned by commit SHA);permissions:block grantswriteat workflow or job level (inlinewrite-all/{ contents: write }also rejected).Local composite actions (
uses: ./...) are part of this repository and remain allowed. Success output:✅ 5 allowlisted action pin(s) across 8 workflow(s) verified.scripts/check-actions-policy.test.mjscovers each of those rules, local actions, commented-out entries,.yamlfiles, missing/malformed allowlists, and asserts thatdocs/CI.mdstays in sync with the reviewed allowlist..github/workflows/actions-policy.ymlrunsnode --test+ the checker on PRs and pushes that touch workflows, the allowlist, the checker, orpackage.json.Verification
Run locally on this branch:
js-yaml; each pin was checked against the upstream repo withgit ls-remote, and the action metadata at each pinned SHA was fetched to confirm it exists.action_requiredrather than running here; the two path-scoped jobs that do run unapproved (Docs link check,Environment template check) passed. A throwaway fork-only run ofactions/checkout@11d5960…,pnpm/action-setup@b906aff…,dtolnay/rust-toolchain@b725eda…(withtoolchain: stable), andSwatinem/rust-cache@d1527c8…completed successfully onubuntu-latest, confirming every pin executes.scripts/check-bindings-cli.test.mjs(3/3),scripts/web-ci.test.mjs,scripts/check-env-examples.mjs+ tests (6/6),scripts/check-deploy-docs.mjs,scripts/check-links.js(43 local links, includesdocs/CI.md).pnpm line-lengths:checkandscripts/check-line-lengths.test.mjsfail on this contributor's Windows machine for pre-existing, unrelated reasons: the test harness builds paths withnew URL(...).pathname(C:\...becomes/C:/...), and the checker compares the allowlist entryapps/web/package.jsonagainst a\-separated path, so an already-allowlisted line is reported. Neither file is touched here and both pass on the Ubuntu runners CI uses; I left them alone to keep this PR scoped.web,contract,coverage,bindings) exercise unchanged application/contract code; their configurations are unmodified apart from the pins, and this PR's ownActions policyjob verifies the pins.Repository settings required (maintainers, not representable in git)
In Settings → Actions → General:
pnpm/action-setup,dtolnay/rust-toolchain,Swatinem/rust-cache. Nothing else is needed by the current workflows.With those settings, every action used by all eight workflows is inside the allowed set;
docs/CI.mdrecords the same list so future changes are reviewable against it.Supply-chain checklist
package.jsononly gains two script aliases); no lockfile changes.toolchain: stableinput; triggers andcontents: readpermissions are untouched.Closes #489