README
¶
gh-actlock
gh-actlock is a GitHub CLI extension that improves the security of your GitHub Actions workflows by automatically pinning action references to specific commit SHAs.
Features
- Pins GitHub Actions and shared workflows to full commit SHAs
- Handles all formats: tags, branches, and already-pinned SHAs
- Preserves original references as in-line comments
- Implements local HTTP caching to reduce API calls
- Preserves file formatting, indentation, and syntax
- Updates pinned SHAs to latest[^1] versions with
-u/--updateflag
Why Pin GitHub Actions?
GitHub Actions are typically referenced using a tag or branch name:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@main
This approach has security implications:
- Tags can be moved to point to different commits
- Branches can be updated with new, potentially malicious code
- Supply chain attacks become possible if action repositories are compromised
By pinning actions to specific commit SHAs, you make your workflows more secure:
steps:
- uses: actions/checkout@a81bbbf8298c0fa03ea29cdc473d45769f953675 # v4
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # main
Installation
Prerequisites
- GitHub CLI (
gh) installed
Install as a GitHub CLI extension
gh ext install esacteksab/gh-actlock
Usage
[!NOTE]
gh-actlockis designed to be run in the root directory of your Git repository. It expects a.github/or.github/workflows/directory containing your action or workflow files.
Commands
gh actlock: Default command to pin actions and shared workflows to the full commit SHA of the current ref.gh actlock -uorgh actlock --update: Update existing pinned SHAs to latest[^1] versions.gh actlock clear -forgh actlock clear --force: Clear the local cache.
Navigate to your repository's root directory and run:
gh actlock
The extension will:
- Find all action files in
.github/or workflow files in.github/workflows/. - Analyze each file and identify any action or shared workflow references.
- Resolve non-SHA references (tags, branches) to their corresponding full commit SHAs.
- Update each action or workflow file with the full commit SHA of the existing reference, preserving the original reference as an inline comment.
[!IMPORTANT] Make sure you run the command from your repository's root directory where the
.github/directory is located.
Updating Pinned Actions and Shared Workflows
To update actions and shared workflows that are already pinned to SHAs to their latest[^1] versions, use the -u or --update flag:
gh actlock -u
# or
gh actlock --update
This will:
- Find all action files in
.github/or workflow files in.github/workflows/ - Analyze each file and identify any action or shared workflow references
- Check if newer versions are available
- Update the existing full commit SHA to the latest[^1] version's full commit SHA while preserving the original reference in an inline comment
For shared workflows, it converts references like uses: owner/.github/.github/workflows/file.yml@tag to use the corresponding SHA while keeping the original tag as a comment.
Managing Local Cache
The extension maintains a local cache to reduce API calls. You can clear this cache using the clear command with the required -f or --force flag:
[!NOTE] The
-f/--forceflag is required as a safeguard to prevent accidental cache deletion.
gh actlock clear -f
# or
gh actlock clear --force
This will remove the application's cache directory located at:
- Linux/BSD:
$XDG_CACHE_HOME/gh-actlock(typically~/.cache/gh-actlock) - macOS:
~/Library/Caches/gh-actlock - Windows:
%LocalAppData%\gh-actlock(typicallyC:\Users\<username>\AppData\Local\gh-actlock)
Limitations
- Only GitHub-hosted actions and shared workflows are pinned (
uses: owner/repo@refanduses: owner/.github/.github/workflows/file.yml@ref) - Local actions and Docker actions are skipped
- Requires proper GitHub authentication for higher API rate limits
- Uses the default
yamllintcomment configuration (e.g. two spaces prior to a comment (#), one space after)
Authentication
[!TIP] For higher REST API rate limits, create a GitHub token and set
GITHUB_TOKENas an environment variable:
export GITHUB_TOKEN=your_token_here
gh actlock
Upgrade gh actlock
gh ext upgrade actlock
A Note About Latest
When creating a release in GitHub, you have the option to Set as latest release. This is a mutable tag, that exists at https://github.com/org/repo/releases/latest[^2]. Latest can be a bit misleading as it may not be the highest numerical valued tag, meaning you could have v1.0.0, v2.0.0 and v3.0.0 and the v2.0.0 release could have the latest tag set. actlock uses the REST API Endpoint to get the latest release when passing the -u/--update flag. This may not be the desired behavior. In the previously mentioned scenario, it is possible that you may have something like uses: actions/foo@v3, but actions/foo@v2 is tagged latest so when passing -u/--update to actlock, it will be pinned at uses: actions/foo@sha2 #v2.0.0 instead of actions/foo@sha3 #v3.0.0. This behavior is being tracked in issue #74, I'm not entirely sure how I want to handle this edge case, but I did want to document it here in case you experienced this.
Examples
Pinning Actions Example
Before:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
After:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a81bbbf8298c0fa03ea29cdc473d45769f953675 # v4
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3
Pinning Shared Workflows Example
Before:
name: Tools - Check
on:
pull_request:
branches:
- "main"
paths:
- "**.go"
- "**.mod"
- "**.sum"
- ".goreleaser.yaml"
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true
permissions:
contents: read
jobs:
goreleaser-check-reusable:
uses: esacteksab/.github/.github/workflows/tools.yml@0.5.3
After:
name: Tools - Check
on:
pull_request:
branches:
- "main"
paths:
- "**.go"
- "**.mod"
- "**.sum"
- ".goreleaser.yaml"
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true
permissions:
contents: read
jobs:
goreleaser-check-reusable:
uses: esacteksab/.github/.github/workflows/tools.yml@7da1f735f5f18ecf049b40ab75503b1191756456 # 0.5.3
Keeping Pinned Actions Updated
You can keep your pinned actions up-to-date using:
- GitHub Dependabot - Native GitHub solution for automated updates
- Renovate - Third-party solution with advanced configuration options
These tools will automatically create pull requests to update your pinned SHAs when new versions of actions are released.
Troubleshooting
actlock supports an environment variable ACTLOCK_DEBUG being set to "true", "TRUE", "True", or "1" to enable verbose logging. Ideally this verbose logging can help you diagnose and understand why something isn't working as expected. If you believe you found a bug, please open an issue. Thank you!
License
MIT Licensed
Contributing
Contributions welcome! Please feel free to submit a pull request.
Similar Tools
I built actlock because I was manually pinning actions often, and each time I did, I told myself "One day, I will automate this.". The curse of knowing a how to write code, but not to see if someone else already did it, I didn't think to see if there was an existing tool. Only when trying to figure out what to call the tool, did I find a bunch of others. actlock may not be the right tool for you, but it doesn't mean that you shouldn't pin your actions to a SHA. These other tools do that (and maybe more!), I have no experience with them, so your mileage my vary.
[^1]: See Latest
Documentation
¶
There is no documentation for this package.