What is this?
July 9, 2026 · View on GitHub
This document explains how to maintain SHA-pinned GitHub Actions in this project.
All actions are pinned to commit SHAs (not version tags) to reduce supply-chain risk.
Table of Contents ᐞ
Overview ᐞ
This project uses SHA-pinned GitHub Actions instead of floating version tags. That gives:
- Security: Prevents compromised tags from silently changing CI behavior.
- Reproducibility: The same action code runs every time.
- Auditability: It is easy to track exactly which code is running.
- Maintenance cost: Updates are manual and must be verified.
Workflows with pinned actions ᐞ
.github/workflows/main.ymlfor linting, tests, and builds..github/workflows/codeql-analysis.ymlfor CodeQL scanning..github/workflows/scorecard.ymlfor supply-chain scoring..github/workflows/vulnerability-scan.ymlfor vulnerability scanning.
Current Action Pins ᐞ
The current pin list is generated from .github/workflows/*.yml so it does not
become stale.
Run this command to print current pins as markdown:
bash scripts/check-action-updates.sh --current-pins-md
If you are on the host machine, run it in the dev container (make bash) or in
your Dev Container terminal.
How to Update Actions ᐞ
Step 1: Identify the action to update ᐞ
Check which version is currently pinned in workflow files. Example:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
The comment is the version tag. The SHA appears before the comment.
Step 2: Get the new commit SHA ᐞ
Use one of these methods to find the SHA for a new version.
Method A: git ls-remote (recommended) ᐞ
# Get SHA for a specific version tag.
git ls-remote --tags https://github.com/actions/checkout.git \
refs/tags/v6.0.3 | awk '{print \$1}'
Method B: GitHub CLI ᐞ
# If GitHub CLI is installed.
gh api repos/actions/checkout/git/refs/tags/v6.0.3 --jq '.object.sha'
Method C: curl + jq ᐞ
# Get latest release metadata.
curl -s https://api.github.com/repos/actions/checkout/releases/latest \
| jq '.target_commitish'
Step 3: Update workflow files ᐞ
Update every occurrence of that action across workflows.
Example: update actions/checkout from v6.0.2 to v6.0.3.
Before:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
After:
uses: actions/checkout@ABC123DEF456... # v6.0.3
Make sure to:
- Update all occurrences of that action.
- Keep the version tag in the comment.
- Use the full 40-character SHA.
Step 4: Verify the update ᐞ
Ensure all references were replaced:
# Search for old version.
grep -r "v6.0.2" .github/workflows/
# Verify new version.
grep -r "v6.0.3" .github/workflows/
Step 5: Create a pull request ᐞ
- Create a branch:
git checkout -b chore/update-github-actions - Commit updates with a clear message.
- Push and open a PR.
- Verify CI passes with new action versions.
- Merge after approval.
Checking for Updates ᐞ
Method 1: Dependabot notifications ᐞ
Dependabot can suggest action updates, but you still need to verify and update the SHA manually.
Dependabot updates version tags in references. It does not select and verify the new commit SHA for you.
Typical flow:
- Review the Dependabot PR suggestion.
- Fetch the SHA for that version.
- Update the SHA in workflow files.
Method 2: Automated check script (recommended) ᐞ
This repository includes an update-check script:
- Location:
scripts/check-action-updates.sh
Run it with:
make check-action-updates
If you are already inside the dev container:
bash scripts/check-action-updates.sh
What it does:
- Discovers pinned actions dynamically from
.github/workflows/*.yml. - Compares each pin against the latest compatible release tag.
- Resolves the full commit SHA for discovered updates.
- Shows summary output and source lines for each finding.
- Reports discovery warnings such as unpinned refs.
- Detects "same version, new SHA" refreshes when a tag is repointed or an annotated tag resolves to a new commit.
Example output:
================================================================================
GitHub Actions Update Checker
================================================================================
Checking 7 GitHub Actions for updates...
UPDATE AVAILABLE: actions/setup-node
v6.3.0 -> v6.3.1
SHA: 53b83947abc123def456...
Short: 53b83947
================================================================================
Summary
================================================================================
Total actions checked: 7
Discovery warnings: 0
Up-to-date: 5
Updates available: 2
Exit codes:
0: no discovery warnings and no updates.1: updates are available.2: discovery warnings found.
Use in CI:
# .github/workflows/check-updates.yml
name: Check Action Updates
on:
schedule:
- cron: '0 9 * * 1'
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- run: bash scripts/check-action-updates.sh
Requirements:
gittimeoutbash
Important behavior:
- The script tracks updates in the same major version line by default.
- This avoids false positives from alternate tag streams in some repositories.
- A finding can show
vX.Y.Z -> vX.Y.Z (pin SHA refresh)when the version stays the same but the tag's commit SHA has changed. - The script continues checks even when discovery warnings are present.
- Move to a new major version manually after reviewing release notes.
Note: the script reports updates but does not apply them.
Method 3: GitHub security alerts ᐞ
GitHub can notify you about:
- Dependabot action update alerts.
- Security vulnerabilities in actions.
- Breaking changes in action releases.
Check: Repository Settings -> Code security and analysis -> Dependabot alerts.
Testing Updates ᐞ
1. Test in a feature branch ᐞ
Always test action updates before merging:
git checkout -b test/action-update
# Make action updates.
git push origin test/action-update
# Create a PR and verify CI passes.
2. Verify action behavior ᐞ
Review release notes for behavioral changes:
Example: https://github.com/actions/checkout/releases/tag/v6.0.3
3. Monitor first run after merge ᐞ
After merge:
- Watch the next CI run carefully.
- Check logs for new warnings or errors.
- Verify behavior still matches expectations.
Understanding SHA Pins ᐞ
What is a SHA pin? ᐞ
A SHA is a cryptographic fingerprint of a specific commit.
- Version tag (mutable):
actions/checkout@v6.0.2 - Commit SHA (immutable):
actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
Why use SHA pins? ᐞ
Tags can be moved. SHAs cannot be changed once published. Pinning SHAs keeps workflow behavior stable and auditable.
How GitHub Actions resolves references ᐞ
GitHub supports both forms:
- Tag:
uses: actions/checkout@v6.0.2 - Full SHA:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - Short SHA:
uses: actions/checkout@de0fac2e
Best Practices ᐞ
Do:
- Keep the version tag in comments for readability.
- Update all instances of the same action together.
- Test updates in a feature branch before merging.
- Review changelogs before updating.
- Prefer full 40-character SHAs.
Do not:
- Mix tags and SHAs for the same action.
- Update only some instances of an action.
- Merge updates without testing.
- Use SHAs from unverified sources.
- Ignore breaking changes.
Troubleshooting ᐞ
"Action not found" error ᐞ
If this appears after updating:
Error: Can't find 'node_modules/...' from action
The SHA may be incorrect. Verify it:
git ls-remote --tags https://github.com/actions/setup-node.git \
refs/tags/v6.3.0 | awk '{print \$1}'
Workflows fail with a new action ᐞ
Diagnose:
- Check the action changelog for breaking changes.
- Read workflow logs for precise errors.
- Reproduce locally if possible.
- Check the GitHub Actions status page.
Then:
- Revert to the previous pin while investigating.
- Open an issue in the action repository if needed.
- Contact maintainers when appropriate.
SHA not found in repository ᐞ
Problem: fetched SHA does not exist.
Verify:
# Confirm repository and tag.
git ls-remote https://github.com/OWNER/REPO.git refs/tags/TAG_NAME
# Confirm tag exists.
git ls-remote https://github.com/OWNER/REPO.git | grep TAG_NAME
Useful Resources ᐞ
FAQ ᐞ
Q: Why not use version tags directly? A: Tags can be retagged or deleted. SHAs are immutable.
Q: Can SHAs be updated automatically? A: You can automate detection, but verification should stay manual.
Q: What if a security patch is released? A: Update the pin quickly after reviewing changelog and CI impact.
Q: How often should actions be updated? A: Apply security fixes quickly and review regular updates monthly.
Q: Can I use short SHAs? A: GitHub supports short SHAs, but full SHAs are recommended.
Last Updated ᐞ
- Date: 2026-04-09
- Updated By: GitHub Copilot
- Next Review: 2026-05-09
See also: doc/README.md and .github/workflows/.