GitHub - TheDen/ghapin: A CLI tool to pin GitHub Actions to commit SHAs for supply-chain security.

3 min read Original article ↗

Go Version License

Tags are mutable. SHAs aren't. Pinning actions to commit SHAs protects your CI from supply-chain attacks.

Install

Download a prebuilt binary

Grab the latest release for your platform from GitHub Releases.

macOS (Apple Silicon)

curl -sL https://github.com/TheDen/ghapin/releases/latest/download/ghapin_darwin_arm64 -o ghapin
chmod +x ghapin
sudo mv ghapin /usr/local/bin/

macOS (Intel)

curl -sL https://github.com/TheDen/ghapin/releases/latest/download/ghapin_darwin_amd64 -o ghapin
chmod +x ghapin
sudo mv ghapin /usr/local/bin/

Linux (x86_64)

curl -sL https://github.com/TheDen/ghapin/releases/latest/download/ghapin_linux_amd64 -o ghapin
chmod +x ghapin
sudo mv ghapin /usr/local/bin/

Linux (ARM64)

curl -sL https://github.com/TheDen/ghapin/releases/latest/download/ghapin_linux_arm64 -o ghapin
chmod +x ghapin
sudo mv ghapin /usr/local/bin/

Windows

Download ghapin_windows_amd64, rename it to ghapin.exe, and add it to a directory in your PATH.

Verify

Go install

go install github.com/TheDen/ghapin@latest

Build from source

git clone https://github.com/TheDen/ghapin.git
cd ghapin
go build -o ghapin .

Quick start

# See what would change
ghapin .github/workflows/*.yaml

# Happy with the output? Write it back
ghapin -w .github/workflows/*.yaml

Usage

ghapin [flags] <files...>
ghapin [command]

Running ghapin with no arguments prints help.

Commands

Command Description
list Discover and list workflow files under .github/workflows/
help Help about any command

Flags

Flag Short Description
--write -w Write pinned output back to the file in-place
--dry-run -n Show what would change, don't produce output
--comment -c Keep the original ref as an inline comment (# v1.29.5)
--verbose -v Log skipped and already-pinned actions
--quiet -q Suppress all progress output on stderr
--include-first-party Pin first-party actions too (actions/*)
--skip-org Skip all actions from this org (repeatable)
--skip-action Skip a specific action by owner/repo (repeatable)
--version Print version
--help -h Print help

-w and -n are mutually exclusive. So are -v and -q.

Examples

Preview before writing

By default ghapin prints the pinned YAML to stdout so you can inspect it, pipe it, or diff it before committing to anything:

ghapin .github/workflows/ci.yaml | diff .github/workflows/ci.yaml -

Write in-place

ghapin -w .github/workflows/*.yaml

Dry-run

See which actions would be pinned without producing any file output:

ghapin -n .github/workflows/*.yaml
  .github/workflows/ci.yaml: crate-ci/typos@v1.29.5 -> 11ca4583f2f3
  .github/workflows/ci.yaml: docker/build-push-action@v5 -> ca052bb54ab0

Keep the original ref as a comment

ghapin -wc .github/workflows/*.yaml
- uses: crate-ci/typos@11ca4583f2f3f74c7e7785c0ecb20fe2c99a4308 # v1.29.5

Comments are off by default. This avoids stale comments if a tool like Dependabot later bumps the SHA without updating the comment.

Discover workflow files

.github/workflows/ci.yaml
.github/workflows/release.yml

Useful for scripting:

Pin first-party actions

By default actions/* (checkout, setup-node, cache, etc.) are skipped. To pin them too:

ghapin -w --include-first-party .github/workflows/*.yaml

Skip specific orgs or actions

ghapin -w --skip-org docker --skip-org google .github/workflows/*.yaml
ghapin -w --skip-action hashicorp/setup-terraform .github/workflows/*.yaml

Verbose output

See everything ghapin considers, including what it skips and why:

ghapin -nv .github/workflows/ci.yaml
  ci.yaml: skip actions/checkout (org "actions" excluded)
  ci.yaml: crate-ci/typos@v1.29.5 -> 11ca4583f2f3
  ci.yaml: skip docker/build-push-action (already pinned)

Testing

License

GNU General Public License v2.0 (GPL-2.0).

See LICENSE.