Skip to content

Pin all third-party GitHub Actions to commit SHAs#2724

Open
thedavidmeister wants to merge 6 commits into
mainfrom
2026-06-13-issue-620
Open

Pin all third-party GitHub Actions to commit SHAs#2724
thedavidmeister wants to merge 6 commits into
mainfrom
2026-06-13-issue-620

Conversation

@thedavidmeister

Copy link
Copy Markdown
Contributor

Fixes #620 (the GitHub Actions slice of "pin all deps so we don't get ledgered").

What the issue wanted

Pin floating dependency refs for supply-chain safety so a moved upstream
tag can't silently inject code into our pipeline.

What this does

The npm / cargo / nix dependency trees are already pinned by their
committed lockfiles (package-lock.json, Cargo.lock, flake.lock,
soldeer.lock). The one surface with no lock equivalent was GitHub
Action uses: refs, every one of which pointed at a mutable tag
(@v4, @v2, @v30, ...). That is the literal "get ledgered" vector
(the tj-actions/changed-files compromise moved a @v* tag).

This pins all 11 distinct third-party actions to their current full
40-hex commit SHA, with a # vX comment for readability:

action tag
actions/checkout v4 / v2
actions/cache v4
actions/setup-node v4
nixbuild/nix-quick-install-action v30
cachix/cachix-action v15
nix-community/cache-nix-action v6 / v7
Swatinem/rust-cache v2
jlumbroso/free-disk-space v1.3.1
softprops/action-gh-release v2

Each SHA is the current tip of the tag it replaces, so behavior is
unchanged; v2 checkouts stay on v2.

First-party rainlanguage/* shared-CI refs (rainix / github-chore
reusable workflows + actions) are intentionally left at @main — the
org tracks those at main on purpose, so pinning them is an org-wide call
rather than this repo's.

Regression guard (discriminating test)

  • script/check-pinned-actions.sh scans every workflow uses: line and
    prints OK iff each third-party ref is a 40-hex SHA, else
    UNPINNED: <ref> ... naming the offenders (skips rainlanguage/*,
    local ./ actions, docker://). Mirrors the existing
    script/check-published-deploy-constants.sh FFI-oracle pattern.
  • test/PinnedActions.t.sol runs it via vm.ffi and asserts the output
    is exactly OK. This is discriminating, not "it runs": reintroduce
    any floating ref and the test reds with that exact ref.

Verification

  • forge test --match-path test/PinnedActions.t.sol
    [PASS] testEveryThirdPartyActionIsShaPinned.
  • Discrimination proven: temporarily reverting one ref to
    actions/checkout@v4 makes the script print
    UNPINNED: actions/checkout@v4 (so the test would red); restoring it
    returns OK.
  • Every pinned SHA re-checked against the live tag resolution — all 11
    match.
  • CI-only change: no src/ content, so no soldeer publish and no
    deployed-bytecode change.

Note: the full forge test suite has a pre-existing compile failure
unrelated to this PR — test/concrete/parser/RaindexV6SubParser.routingTokenDecimalsAndMasks.t.sol
imports rainlang-0.1.2/... while the repo migrated to rainlang-0.1.5
(remappings, foundry.toml, soldeer.lock all 0.1.5). It is byte-identical
to main here and untouched by this PR; the new test was run with that
file isolated to confirm it passes.

🤖 Generated with Claude Code

Every `uses:` reference to a third-party GitHub Action in
`.github/workflows/` was pinned only to a mutable tag (`@v4`, `@v2`,
`@v30`, ...). A mutable tag lets whoever controls the upstream tag run
arbitrary code in our CI the moment it moves -- the supply-chain hole
that issue #620 ("pin all deps so we don't get ledgered") calls out, and
the exact vector behind the tj-actions/changed-files compromise.

Pin all 11 distinct third-party actions to their current full 40-hex
commit SHA, keeping a `# vX` comment for readability:

  actions/checkout            v4 / v2
  actions/cache               v4
  actions/setup-node          v4
  nixbuild/nix-quick-install-action  v30
  cachix/cachix-action        v15
  nix-community/cache-nix-action     v6 / v7
  Swatinem/rust-cache         v2
  jlumbroso/free-disk-space   v1.3.1
  softprops/action-gh-release v2

First-party `rainlanguage/*` shared-CI refs (rainix / github-chore
reusable workflows and actions) are intentionally left at `@main`: the
org tracks those at `main` on purpose, so pinning them is an org-wide
decision rather than this repo's. npm / cargo / nix dependency trees are
already pinned by their committed lockfiles (package-lock.json,
Cargo.lock, flake.lock, soldeer.lock); action refs were the one surface
with no lock equivalent.

Add a regression guard so a floating ref cannot creep back in:

- `script/check-pinned-actions.sh` scans every workflow `uses:` line and
  prints `OK` iff each third-party ref is a 40-hex SHA, else
  `UNPINNED: <ref> ...` listing the offenders (skips `rainlanguage/*`,
  local `./` actions and `docker://` refs). Mirrors the existing
  `script/check-published-deploy-constants.sh` FFI-oracle pattern.
- `test/PinnedActions.t.sol` runs that script via `vm.ffi` and asserts
  the output equals exactly `OK`. Reintroducing e.g. an unpinned
  `actions/checkout` reds the test with the exact offending ref.

CI-only change: no `src/` content changes, so no soldeer publish, no
deployed-bytecode change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@thedavidmeister thedavidmeister self-assigned this Jun 13, 2026
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@thedavidmeister, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 37 minutes. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8b1e7bd1-772e-4c27-ab57-67afb972eb4f

📥 Commits

Reviewing files that changed from the base of the PR and between f887bca and a8fa4e9.

📒 Files selected for processing (16)
  • .github/workflows/copilot-setup-steps.yml
  • .github/workflows/deploy-subgraph.yaml
  • .github/workflows/manual-rs-release.yml
  • .github/workflows/npm-package-release.yml
  • .github/workflows/test-js-bindings.yaml
  • .github/workflows/test-ui-components.yaml
  • .github/workflows/test-webapp.yaml
  • .github/workflows/vercel-docs-preview.yaml
  • .github/workflows/vercel-docs-prod.yaml
  • .github/workflows/vercel-preview.yaml
  • .github/workflows/vercel-prod.yaml
  • .github/workflows/wasm-artifacts.yaml
  • .github/workflows/wasm-browser-test.yaml
  • .github/workflows/wasm-test.yaml
  • script/check-pinned-actions.sh
  • test/PinnedActions.t.sol
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2026-06-13-issue-620

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.

❤️ Share

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

thedavidmeister and others added 4 commits June 15, 2026 17:27
Rework the action-pinning approach: instead of inline-pinning the shared
nix/cachix CI preamble actions (checkout, nix-quick-install, cachix-action,
cache-nix-action, rust-cache, actions/cache, action-gh-release) in each
raindex workflow, consume the rainix composite actions
(rainlanguage/rainix/.github/actions/*) that already pin every one of those
SHAs once. The pins are inherited and maintained in rainix.

Twelve workflows now delegate their preamble to the composites:
copilot-setup-steps, deploy-subgraph, manual-rs-release, npm-package-release,
test-js-bindings, test-ui-components, test-webapp, vercel-docs-preview,
vercel-docs-prod, wasm-artifacts, wasm-browser-test, wasm-test. Workflows that
free disk space between checkout and nix-quick-install (or do an ssh-key
checkout) pass checkout: false and run checkout themselves first;
nix-cachix-setup's gc-max-store-size-linux carries each workflow's store
budget.

free-disk-space and setup-node have no rainix composite wrapper, so they stay
inline SHA-pinned. The vercel-preview / vercel-prod webapp deploys keep their
inline pins too; they are being migrated to the rainix-vercel reusable
workflow separately.

check-pinned-actions.sh / PinnedActions.t.sol require a SHA pin for every
third-party action that remains inline and exempt first-party rainlanguage/*
refs, so a workflow satisfies the invariant either by inline-pinning or by
delegating to a rainix composite that pins it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Take main's simplified npm-blacklist job (checkout@v4, cache-nix@v7,
gc-max-store-size 8G, npm install --no-check) in both vercel workflow
files; the full vercel build is in the reusable rainix-vercel workflow.

Co-Authored-By: Claude <noreply@anthropic.com>
…A refs in vercel-preview and vercel-prod npm-blacklist jobs
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.

pin all deps

1 participant