Repository navigation
CI: Pin the third-party actions by commit, scope the workflow tokens and drop persisted checkout credentials - #12315
Conversation
A tag such as oven-sh/setup-bun@v2.1.2 is a movable pointer: whoever can push to that repository decides what runs in these jobs. The 25 third-party references in the five hand-written workflows now point at the commit the tag resolved to today, with the tag kept as a comment so the version is still readable. ruby/setup-ruby@master was a branch, it is pinned to the v1.329.0 release. First-party actions/* stay on their tags. pullfrog.yml is left as its header asks.
…h the token push.yml, changelog.yml and discord.yml had no permissions block, so every job received the repository's default token scopes. None of their jobs writes back to GitHub: push.yml builds, tests and uploads artifacts, changelog.yml posts to Discord with its own token, and discord.yml only calls a webhook. push.yml and changelog.yml get a read-only token, discord.yml gets none at all, which also shrinks what a pull_request_target run can reach.
actions/checkout writes the job token into .git/config by default, so every later step, including third-party actions and the packages they install, can read it. None of the 13 checkouts in push.yml, changelog.yml and copilot-setup-steps.yml pushes with git, so they no longer keep the token. The claude.yml and pullfrog.yml checkouts are untouched: those agents commit back and their token path is theirs to decide.
There was a problem hiding this comment.
ℹ️ Minor suggestions only. All the pins check out — one consistency nit inline, plus the merge-time checks below.
Reviewed changes
Reviewed the 5 hand-written workflows this PR touches (pullfrog.yml intentionally left as its header requests).
- Third-party actions pinned to commit SHAs —
oven-sh/setup-bun,rharkor/caching-for-turbo,anthropics/claude-code-action,ruby/setup-rubyandshivammathur/setup-phpnow reference full-length commit SHAs with the version kept as a trailing comment. - Workflow token scoping —
push.ymlandchangelog.ymladdpermissions: contents: read;discord.ymladdspermissions: {}. - Checkout credentials dropped — 13
actions/checkoutsteps gainpersist-credentials: false; the two agent workflows that commit back are left untouched.
Every pinned SHA resolves to the upstream tag it claims — I checked v2.1.2, v2.3.11, v1.0.249, v1.329.0 and 2.40.0, and the two annotated tags dereference to exactly the pinned commits. None of the restricted workflows performs a git push, and none of the in-scope actions authenticates a GitHub API call with the token (IdanHo/action-discord reads the event payload off disk; discord-poster/post.ts fetches the public release unauthenticated), so the narrowed permissions and stripped credentials are safe here.
ℹ️ Merge-time operational checks
Two follow-ups ride on this change but live outside the diff.
Technical details
# Pinned-action operational follow-ups
## Affected sites
- `.github/workflows/*.yml` — 25 third-party refs now frozen to SHAs
- `.github/workflows/discord.yml`, `push.yml`, `changelog.yml` — new `permissions` blocks
## Required outcome
- Confirm the repo's **allowed-actions** policy before merge. If it restricts third-party actions by tag pattern (`owner/action@vX`), the new SHA refs will not match and every job using them will be refused — switch patterns to `owner/action@*` first.
- Add dependency automation (e.g. a `.github/dependabot.yml` `github-actions` entry) so the frozen SHAs still receive upstream security patches; otherwise this trades a movable-tag risk for a stale-pin risk.
## Open questions for the human
- Is the allowed-actions policy currently tag-based (the PR body raises this)?
- Should `pullfrog.yml`'s `pullfrog/pullfrog@v0` (privileged: `id-token: write`, `contents: write`) also be pinned, via the upstream Pullfrog template?deepseek-v4.1-flash | 𝕏
| - uses: actions/checkout@main | ||
| - uses: oven-sh/setup-bun@v2.1.2 | ||
| with: | ||
| persist-credentials: false |
There was a problem hiding this comment.
Since this checkout step is being hardened anyway: it still tracks the floating @main branch, unlike the actions/checkout@v6 used in every other workflow. @main is the least reproducible ref and doesn't match the PR's own "first-party actions stay on their tags" rule — bump to @v6.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Hello, three commits on the hand-written workflows, pullfrog.yml left as its header asks.
ruby/setup-ruby@masteris pinned to the v1.329.0 release. First-party actions stay on their tags.pull_request_target.Why: a tag is a movable pointer, and these jobs run on every pull request with the default token while changelog.yml holds the Discord token. The tj-actions incident (CVE-2025-30066) went through exactly that door.
There is no update bot here, a dependabot
github-actionsentry would keep the pins current, happy to add it. If the allowed-actions setting uses tag patterns, switch them toowner/action@*first, SHA refs do not match the tag form.Found and fixed by Plumber's analysis, reviewed and submitted by me. I'm also a long time user of Remotion