Update GitHub Actions configurations to use hashpins, instead of mutable pins, in a Dependabot-compatible way
Project description
gha-hashpinner
Finds mutable pins in GitHub Actions config and replaces them with immutable commit SHAs.
This is a security best practice that protects against supply chain attacks.
The immutable hashpins generated by this tool include version comments which are Dependabot-compatible.
⚠️ SHA pinning isn't a perfect solution and GitHub should be ashamed. If someone opens a PR to update a SHA pin, close it and let Dependabot do it instead (or manually verify the SHA is a member of the correct repo).
Example
❌ Mutable pins are a bad practice (you might get pwned!):
jobs:
my-job:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
✅ This tool will convert them to immutable pins:
jobs:
my-job:
steps:
- name: "Checkout"
uses: "actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5" # v4
Install
uv tool install gha-hashpinner
Usage
From a GitHub repository containing GitHub Actions workflows in .github/workflows:
gha-hashpinner .
Or, update a specific workflow file:
gha-hashpinner .github/workflows/my-workflow.yml
GitHub API rate limiting
The GitHub API rate-limits unauthenticated requests to 60/hour.
You may want to provide a token with the --token= argument to avoid rate limits.
This tool only needs read access.
It's very important to minimize access granted to any tool to only what's required. Only use fine-grained personal access tokens (PATs) with no extra permissions. Never click the "Add permissions" button.
In other words, keep everything default. The only thing selected in the fine-grained PAT UI should be "Public repositories (Read-only access to public repositories)". If you need to run this tool against private repositories, select "All repositories" or "Only select repositories".
With GitHub Actions
TODO
With pre-commit / prek
TODO
Alternatives
- https://github.com/azat-io/actions-up: NPM package
- https://github.com/Skipants/update-action-pins: Go package
Why?
I deeply distrust the NPM ecosystem. The Go package above is not user-friendly to install.
I wanted something I could install with uv tool install.
LLMs plus a dash of review and engineering judgement make it fast and easy to build tools like this.
Limitations
- Does not update your actions -- only pins them immutably to the same version they're already pinned to. I recommend using Dependabot (with a cooldown) to upgrade your actions after pinning with this tool.
- This tool detects mutable refs with regex, i.e. a 40-character hexadecimal string is considered to be an immutable ref. There's no way to be sure without making API calls. See the relevant issue (#13) for details.
- When not given an explicit file path, only checks workflow files in
.github/workflows.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gha_hashpinner-0.0.3.tar.gz.
File metadata
- Download URL: gha_hashpinner-0.0.3.tar.gz
- Upload date:
- Size: 63.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d41e7b5cefdaa0665508af58eb900d397f27c1449f2f621b53cc4e6d3e7949ec
|
|
| MD5 |
32ace00b2c3064d7f18c03306e7a46db
|
|
| BLAKE2b-256 |
4fa61d387293146b1ce3a03f5fa155b0d227e4a4aad68e2d89ea9c6a61f2372d
|
Provenance
The following attestation bundles were made for gha_hashpinner-0.0.3.tar.gz:
Publisher:
publish.yml on mfisher87/gha-hashpinner
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gha_hashpinner-0.0.3.tar.gz -
Subject digest:
d41e7b5cefdaa0665508af58eb900d397f27c1449f2f621b53cc4e6d3e7949ec - Sigstore transparency entry: 1201068439
- Sigstore integration time:
-
Permalink:
mfisher87/gha-hashpinner@0d0a8232af6c10e1fd80b582d600f284cb82b832 -
Branch / Tag:
refs/tags/0.0.3 - Owner: https://github.com/mfisher87
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0d0a8232af6c10e1fd80b582d600f284cb82b832 -
Trigger Event:
release
-
Statement type:
File details
Details for the file gha_hashpinner-0.0.3-py3-none-any.whl.
File metadata
- Download URL: gha_hashpinner-0.0.3-py3-none-any.whl
- Upload date:
- Size: 15.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
17fc5570dd76e1f5e376147f7fbc6d0d668bdb8d67c74b469f91d8151dd96d7b
|
|
| MD5 |
0cba64624f7ee1bdc17a8e67d4af0b7d
|
|
| BLAKE2b-256 |
9a61a4a412cf2bfaf8c970b9c2d0b061dd00f4f463b692439b297301a2aa9e32
|
Provenance
The following attestation bundles were made for gha_hashpinner-0.0.3-py3-none-any.whl:
Publisher:
publish.yml on mfisher87/gha-hashpinner
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gha_hashpinner-0.0.3-py3-none-any.whl -
Subject digest:
17fc5570dd76e1f5e376147f7fbc6d0d668bdb8d67c74b469f91d8151dd96d7b - Sigstore transparency entry: 1201068449
- Sigstore integration time:
-
Permalink:
mfisher87/gha-hashpinner@0d0a8232af6c10e1fd80b582d600f284cb82b832 -
Branch / Tag:
refs/tags/0.0.3 - Owner: https://github.com/mfisher87
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0d0a8232af6c10e1fd80b582d600f284cb82b832 -
Trigger Event:
release
-
Statement type: