Every uses: in .github/workflows/ now carries a full 40-character commit SHA with its release in a trailing comment.
A tag is a mutable pointer. actions/checkout@v7 is whatever the publisher last moved v7 to, so using one is not trusting the version that was reviewed — it is trusting every future version, including whatever gets pushed by whoever compromises the publisher's account. That is exactly the shape of the tj-actions/changed-files compromise: no repository changed a line, the tags moved underneath them, and the action started dumping runner memory into public build logs.
Action
Pinned to
Release
actions/checkout
3d3c42e5…
v7.0.1
actions/setup-node
82076278…
v7.0.0
actions/upload-artifact
043fb46d…
v7.0.1
actions/download-artifact
3e5f45b2…
v8.0.1
docker/setup-buildx-action
594f3bf4…
v4.4.0
docker/login-action
dbcb8138…
v4.6.0
docker/build-push-action
c3c9e263…
v7.4.0
Each SHA was resolved from the major tag through the GitHub API and then checked against the exact release tag — every major tag currently points at the release named beside it, so no pin silently moves anyone to a different version than they were already running. This is a no-op for behavior.
dataaxiom/ghcr-cleanup-action was already pinned — it is the one third-party action here, and it is handed packages: write and deletes things — so it only picks up the trailing-version convention. Its comment loses the "pinned rather than a moving major tag" framing, which stops being what distinguishes it once everything else is pinned too.
The two uses: ./.github/workflows/… entries in release.yml and publish.yml are local paths, not actions. They always resolve inside the commit already running, and there is no SHA to pin.
Dependabot already covers this..github/dependabot.yml has a weekly github-actions entry, and Dependabot updates the SHA and the version comment together, so staying current costs nothing.
Follow-on, not in this PR: once this merges, the repository's sha_pinning_required setting gets turned on, which makes an unpinned ref fail the run instead of quietly resolving. The order matters — flipping it first would break main on the next push. The comment at the top of ci.yml is written for that end state.
Translations: adds none. No user-visible strings — workflow files only.
Testing: all four workflows re-parse as YAML. ci.yml is exercised by this PR's own build check, which is the real test of the checkout and setup-node pins. publish.yml, release.yml and cleanup.yml do not run on a PR; their pins are verified by resolution against the API rather than by execution, and the next weekly release is the first live run.
Every `uses:` in `.github/workflows/` now carries a full 40-character commit SHA with its release in a trailing comment.
A tag is a mutable pointer. `actions/checkout@v7` is whatever the publisher last moved `v7` to, so using one is not trusting the version that was reviewed — it is trusting every future version, including whatever gets pushed by whoever compromises the publisher's account. That is exactly the shape of the tj-actions/changed-files compromise: no repository changed a line, the tags moved underneath them, and the action started dumping runner memory into public build logs.
| Action | Pinned to | Release |
| --- | --- | --- |
| `actions/checkout` | `3d3c42e5…` | v7.0.1 |
| `actions/setup-node` | `82076278…` | v7.0.0 |
| `actions/upload-artifact` | `043fb46d…` | v7.0.1 |
| `actions/download-artifact` | `3e5f45b2…` | v8.0.1 |
| `docker/setup-buildx-action` | `594f3bf4…` | v4.4.0 |
| `docker/login-action` | `dbcb8138…` | v4.6.0 |
| `docker/build-push-action` | `c3c9e263…` | v7.4.0 |
Each SHA was resolved from the major tag through the GitHub API and then checked against the exact release tag — every major tag currently points at the release named beside it, so no pin silently moves anyone to a different version than they were already running. This is a no-op for behavior.
`dataaxiom/ghcr-cleanup-action` was already pinned — it is the one third-party action here, and it is handed `packages: write` and deletes things — so it only picks up the trailing-version convention. Its comment loses the "pinned rather than a moving major tag" framing, which stops being what distinguishes it once everything else is pinned too.
The two `uses: ./.github/workflows/…` entries in `release.yml` and `publish.yml` are local paths, not actions. They always resolve inside the commit already running, and there is no SHA to pin.
**Dependabot already covers this.** `.github/dependabot.yml` has a weekly `github-actions` entry, and Dependabot updates the SHA and the version comment together, so staying current costs nothing.
**Follow-on, not in this PR:** once this merges, the repository's `sha_pinning_required` setting gets turned on, which makes an unpinned ref fail the run instead of quietly resolving. The order matters — flipping it first would break `main` on the next push. The comment at the top of `ci.yml` is written for that end state.
**Translations:** adds none. No user-visible strings — workflow files only.
**Testing:** all four workflows re-parse as YAML. `ci.yml` is exercised by this PR's own `build` check, which is the real test of the `checkout` and `setup-node` pins. `publish.yml`, `release.yml` and `cleanup.yml` do not run on a PR; their pins are verified by resolution against the API rather than by execution, and the next weekly release is the first live run.
**Merged** 2026-09-15 as coffey-labs/ihasmail@0bde2df69d9b
<sub>Rebuilt from: GH Archive, git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Every
uses:in.github/workflows/now carries a full 40-character commit SHA with its release in a trailing comment.A tag is a mutable pointer.
actions/checkout@v7is whatever the publisher last movedv7to, so using one is not trusting the version that was reviewed — it is trusting every future version, including whatever gets pushed by whoever compromises the publisher's account. That is exactly the shape of the tj-actions/changed-files compromise: no repository changed a line, the tags moved underneath them, and the action started dumping runner memory into public build logs.actions/checkout3d3c42e5…actions/setup-node82076278…actions/upload-artifact043fb46d…actions/download-artifact3e5f45b2…docker/setup-buildx-action594f3bf4…docker/login-actiondbcb8138…docker/build-push-actionc3c9e263…Each SHA was resolved from the major tag through the GitHub API and then checked against the exact release tag — every major tag currently points at the release named beside it, so no pin silently moves anyone to a different version than they were already running. This is a no-op for behavior.
dataaxiom/ghcr-cleanup-actionwas already pinned — it is the one third-party action here, and it is handedpackages: writeand deletes things — so it only picks up the trailing-version convention. Its comment loses the "pinned rather than a moving major tag" framing, which stops being what distinguishes it once everything else is pinned too.The two
uses: ./.github/workflows/…entries inrelease.ymlandpublish.ymlare local paths, not actions. They always resolve inside the commit already running, and there is no SHA to pin.Dependabot already covers this.
.github/dependabot.ymlhas a weeklygithub-actionsentry, and Dependabot updates the SHA and the version comment together, so staying current costs nothing.Follow-on, not in this PR: once this merges, the repository's
sha_pinning_requiredsetting gets turned on, which makes an unpinned ref fail the run instead of quietly resolving. The order matters — flipping it first would breakmainon the next push. The comment at the top ofci.ymlis written for that end state.Translations: adds none. No user-visible strings — workflow files only.
Testing: all four workflows re-parse as YAML.
ci.ymlis exercised by this PR's ownbuildcheck, which is the real test of thecheckoutandsetup-nodepins.publish.yml,release.ymlandcleanup.ymldo not run on a PR; their pins are verified by resolution against the API rather than by execution, and the next weekly release is the first live run.Merged 2026-09-15 as coffey-labs/ihasmail@0bde2df69d
Rebuilt from: GH Archive, git history, session transcript.