Skip to content

Pin all GitHub Actions to commit SHAs#36971

Closed
silverwind wants to merge 1 commit intogo-gitea:mainfrom
silverwind:pin-github-actions-sha
Closed

Pin all GitHub Actions to commit SHAs#36971
silverwind wants to merge 1 commit intogo-gitea:mainfrom
silverwind:pin-github-actions-sha

Conversation

@silverwind
Copy link
Copy Markdown
Member

@silverwind silverwind commented Mar 24, 2026

Pin all third-party GitHub Actions to their current commit SHAs for supply chain security. The tag is preserved as a comment for readability and update tracking. All 20 unique actions across 12 workflow files have been pinned and verified via git ls-remote.

This PR was authored by Claude.

Pin all third-party GitHub Actions to their current commit SHAs
for supply chain security. The tag is preserved as a comment for
readability and update tracking.

Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Mar 24, 2026
@lunny
Copy link
Copy Markdown
Member

lunny commented Mar 24, 2026

Why commit SHAs is more safe?

@bircni
Copy link
Copy Markdown
Member

bircni commented Mar 24, 2026

Why commit SHAs is more safe?

You can move a tag but you cannot move a sha

@wxiaoguang
Copy link
Copy Markdown
Contributor

wxiaoguang commented Mar 24, 2026

I don't think it is a right approach to hard code the commit IDs in workflow file.

You can invent a wheel (or maybe there have been some wheels) to add a "workflow-lock.yaml" and store the branch/tag names & commit IDs in the lock file, and verify them. Manage them together.

@wxiaoguang wxiaoguang marked this pull request as draft March 24, 2026 07:32
@silverwind
Copy link
Copy Markdown
Member Author

silverwind commented Mar 24, 2026

Why commit SHAs is more safe?

It protects from malicious tags. If such a tag is pushed to any branch on the action's repo it would compromise the action which can not happen with SHA pinning. Many repos are doing this, it's not exactly a new technique and recommended by GitHub.

Even with SHA tags, actions can be compromised through their dependencies, nothing can be done about that if a action chooses to unpin their dependencies.

workflow-lock.yaml

What's the difference from a SHA pin?

@wxiaoguang
Copy link
Copy Markdown
Contributor

workflow-lock.yaml

What's the difference from a SHA pin?

Just like package.json and package-lock.json

You can still write - uses: actions/checkout@v6 in workflow yaml, it is clearer and easy to maintain.

@silverwind
Copy link
Copy Markdown
Member Author

workflow-lock.yaml

What's the difference from a SHA pin?

Just like package.json and package-lock.json

You can still write - uses: actions/checkout@v6 in workflow yaml, it is clearer and easy to maintain.

So just a indirection. Yes such a script can be written and there's probably tools on npm for this.

BTW read up on attacks like https://socket.dev/blog/trivy-under-attack-again-github-actions-compromise, many open source repos are getting compromised via actions nowadays, it's a popular attack vector.

@wxiaoguang
Copy link
Copy Markdown
Contributor

wxiaoguang commented Mar 24, 2026

workflow-lock.yaml

What's the difference from a SHA pin?

Just like package.json and package-lock.json
You can still write - uses: actions/checkout@v6 in workflow yaml, it is clearer and easy to maintain.

So just a indirection. Yes such a script can be written and there's probably tools on npm for this.

If there is no such tool, at least, I think the AI prompt should be committed together. Otherwise, people won't know how to upgrade from actions/checkout@v6 to actions/checkout@v7 correctly in the future.


Or, we maintain a "workflow-actions.yaml", and tell AI to use commit ID to update the workflow files

# workflow-actions.yaml
versions:
    actions/checkout: v7

Then AI will read workflow-actions.yaml and update all the workflow files.

I think this approach is pretty simple and clear.

@TheFox0x7
Copy link
Copy Markdown
Contributor

Btw renovate can do this and keep comment for the tag, but I can't exactly set a custom bot up without access to secrets. There's a global github one and @techknowlogick mentioned working on setting it up but not sure where that ended up.


Also to be clear since I looked at this for a long time. This is a theater in part. You're ensuring that the (broken package manager) will checkout the SHA for the action but there's nothing enforcing that the said action is immutable. There's no lock for the dependencies of the action so if anything that the said action uses gets compromised (be it another action, remote file it downloads or a JS package) that's going to run anyway despite the SHA pin.

@silverwind
Copy link
Copy Markdown
Member Author

Yes, sha pinning with renovate will likely be the final solution. The format here is also exactly the one that renovate and other tools support.

@wxiaoguang
Copy link
Copy Markdown
Contributor

wxiaoguang commented Mar 24, 2026

Renovate can be the final answer. And maybe it can also update something like Update Nix flake #36943.

The question is: how should renovate be used?

  1. Make renovate fully automatically update the dependencies
    • The commit IDs can be locked (stay away from supply-chain attack)
    • Attackers make a dependency get a new release: then still supply-chain attack?
  2. Make renovate open a lot of PRs when a dependency gets a new version
    • Will it make a lot of noises in the commit history?
    • Who would really review the details of each change? If no review, it virtually equals to 1
  3. Make renovate open one PR and combine all upgrades together regularly, e.g.: weekly?
    • It virtually equals to 2: who would really review all the changes?
    • Then virtually equal to 1 (better: stay away from supply-chain attack in one week)

@silverwind
Copy link
Copy Markdown
Member Author

I would make renovate open a weekly or bi-weekly pr for maintenance updates with a possible fast-path for security updates. Definitly don't want 1 PR per update as that would be too noisy.

@TheFox0x7
Copy link
Copy Markdown
Contributor

Attackers make a dependency get a new release: then still supply-chain attack?

Renovate usually holds the dependancies for a bit before making a PR if it can - it's configurable though.
Personally I'd prefer smaller bundles instead of a huge change as it's easier to (if you wish) go through one change log than 30 of them.

btw if by "The commit IDs can be locked (stay away from supply-chain attack)" you mean actions part then it's not really protecting against that. It only protects from the action itself being changed but not against it's dependencies. It's a mess.

@silverwind
Copy link
Copy Markdown
Member Author

Attackers make a dependency get a new release: then still supply-chain attack?

Renovate usually holds the dependancies for a bit before making a PR if it can - it's configurable though.

Yes that's "cooldown" and we have it configured for dependabot too:

cooldown:
default-days: 5

@wxiaoguang
Copy link
Copy Markdown
Contributor

btw if by "The commit IDs can be locked (stay away from supply-chain attack)" you mean actions part then it's not really protecting against that. It only protects from the action itself being changed but not against it's dependencies. It's a mess.

Yep, dependency's dependency is another topic. That's why modern package managers have their own recursion lock (go.sum, package-lock.json, etc)

@TheFox0x7
Copy link
Copy Markdown
Contributor

Yeah... don't tell github. They haven't figured that out yet :)

silverwind added a commit to silverwind/gitea that referenced this pull request Apr 25, 2026
Same approach as go-gitea#36971: pin every uses: ref to the full commit SHA with
the version tag in a trailing comment. Adds the helpers:pinGitHubActionDigests
preset so Renovate keeps future bumps in this format and converts any new
tag-pinned actions automatically.

DeterminateSystems/update-flake-lock previously tracked main; pinning to v28
matches what the action's release tagging promises and lets Renovate manage
upgrades the same way as the others.

Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
@silverwind
Copy link
Copy Markdown
Member Author

Superseded by #37050, which includes these SHA pins (in be25801) plus the Renovate config to keep them maintained.

DeterminateSystems/update-flake-lock was tracking main; pinned to v28 there as well. Renovate handles updates from a SHA pin natively, so the updates CLI alternative still works.


Comment by Claude Opus 4.7

@silverwind silverwind closed this Apr 25, 2026
@silverwind silverwind deleted the pin-github-actions-sha branch April 25, 2026 22:03
silverwind added a commit that referenced this pull request Apr 26, 2026
Replaces Dependabot with Renovate. The new setup:

- One PR per ecosystem (GitHub Actions, Go modules + Makefile go-tool
pins, npm, Python via uv, Nix flake), opened weekly on Mondays with a
5-day release-age cooldown. Vulnerability PRs ship next-day via daily
cron + Renovate's `vulnerabilityAlerts` schedule bypass.
- All `uses:` action refs SHA-pinned with patch-level version comments
(same format as #36971, which this supersedes);
`helpers:pinGitHubActionDigests` keeps future bumps in that format.
- `renovatebot/github-action` runtime image pinned via the
upstream-recommended `RENOVATE_VERSION` env + magic comment +
`customManagers:githubActionsVersions` preset, so Renovate keeps the pin
updated.
- Custom regex manager tracks the `*_PACKAGE ?= <import-path>@<version>`
lines in `Makefile` (golangci-lint, swagger, actionlint, etc.) and
groups them into the same Go PR via `matchDatasources: ["go"]`.
- Post-upgrade tasks regenerate `assets/go-licenses.json` (`make tidy`)
and the SVG sprite (`make svg`), gated by an env-level command
allowlist.
- Replaces the standalone `cron-flake-updater` workflow — Renovate's nix
manager tracks `flake.nix` inputs and produces the same `flake.lock`
bump PRs on the regular weekly schedule.
- npm and gomod-replace pins live in `renovate.json5` only;
`updates@17.16.3` reads them from there too, so the standalone
`updates.config.ts` is gone and one source of truth covers both tools.

Fixes: #33386
Signed-off-by: silverwind <me@silverwind.io>
Signed-off-by: TheFox0x7 <thefox0x7@gmail.com>
Co-authored-by: Claude (Opus 4.6) <noreply@anthropic.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants