Metadata-Version: 2.4
Name: gha-hashpinner
Version: 0.0.2
Summary: Update GitHub Actions configurations to use hashpins, instead of mutable pins, in a Dependabot-compatible way
Project-URL: Repository, https://github.com/mfisher87/gha-hashpinner.git
Project-URL: Homepage, https://github.com/mfisher87/gha-hashpinner
Project-URL: Issues, https://github.com/mfisher87/gha-hashpinner/issues
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security
Classifier: Topic :: Utilities
Requires-Python: >=3.12
Requires-Dist: pygithub>=2.8.1
Requires-Dist: pyyaml>=6.0.3
Requires-Dist: rich>=14.3.3
Requires-Dist: typer>=0.24.1
Description-Content-Type: text/markdown

# `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**](https://www.vaines.org/posts/2026-03-24-the-comforting-lie-of-sha-pinning/).
**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!):

```yaml
jobs:
  my-job:
    steps:
      - name: "Checkout"
        uses: "actions/checkout@v4"
```

✅ This tool will convert them to immutable pins:

```yaml
jobs:
  my-job:
    steps:
      - name: "Checkout"
        uses: "actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5"  # v4
```


## Install

```bash
uv tool install gha-hashpinner
```


## Usage

From a GitHub repository containing GitHub Actions workflows in `.github/workflows`:

```bash
gha-hashpinner .
```

Or, update a specific workflow file:

```bash
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](https://en.wikipedia.org/wiki/Principle_of_least_privilege).
**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](pre-commit.com) / [prek](https://prek.j178.dev/)

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

* 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)](https://github.com/mfisher87/gha-hashpinner/issues/13)
  for details.
* When not given an explicit file path, only checks workflow files in
  `.github/workflows`.
