Skip to content

Build1 publisher3 min readPublished

Resolving 31 action pins caught dependency-review-action's v3 tag two majors behind

Pinning a workflow to a commit SHA stops the tag moving under you, and resolving all 31 from the upstream repositories turned up an action whose v3 tag stopped moving at all while its releases reached v5.0.0.

The Engineer · Build desk

Illustration accompanying Resolving 31 action pins caught dependency-review-action's v3 tag two majors behind

What happened

  • The author pinned 31 GitHub Actions to commit SHAs for a set of packaged workflows, resolving every SHA from the upstream repository.
  • actions/dependency-review-action@v3 resolves to a commit with no v3.x.y release tag behind it at all, while the project's newest release is v5.0.0.
  • sigstore/cosign-installer@v3 points at v3.9.1 while the project's newest release is v4.1.2, so the major tag lags its own release list by a major version.
  • aquasecurity/trivy-action publishes only exact versions such as 0.35.0 and no floating v0 tag, so the many workflows written as @master are pinned to a branch.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • decision Dependabot's github-actions ecosystem bumps the SHA and its version comment together, so a team that pins keeps its currency and its reviewability.
  • exposure GitHub issues a fork's pull request a read-only token and withholds secrets, and that enforcement only protects a repository whose workflows stay off pull_request_target.
  • constraint An action that ships no floating major leaves a team no shorthand upgrade, so every version change becomes an explicit edit to the workflow file and a review of what changed.
  • capability A team can now answer from outside its own repository, in about a second, which maintained line its CI is actually running, because the workflow file only ever shows the tag.

A major tag is a pointer, and where it points is a fact about the upstream repository. `uses: actions/checkout@v7` runs whatever commit v7 points at when the job starts. The maintainer moves that tag on every patch release, and so can anyone who takes over the repository or a maintainer's account [3]. A commit SHA cannot be moved, so the code that runs is the code you reviewed until you edit the pin [4]. The convention keeps the file readable: the SHA, then the release in a trailing comment [16].

Resolving one takes a single command. `git ls-remote --tags` against actions/checkout prints v7 and v7.0.1 at the same commit, 3d3c42e5aac5ba805825da76410c181273ba90b1, and that commit is the pin [5]. Annotated tags print two lines for one tag: the tag object, and the commit it points to with a `^{}` suffix. Pin the peeled line [6]. A tag-object SHA in a `uses:` line fails with "unable to resolve action", which the post calls a confusing error for a correct-looking pin [7].

Doing this through the REST API costs more than it looks. Unauthenticated requests are capped at 60 an hour, and one pin can take three of them: release, then tag, then the annotated tag object [8]. Thirty-one actions at three calls each is 93 requests against a ceiling of 60 [10]. `ls-remote` over HTTPS has no such limit and needs no token [9], and the script covered 31 repositories in about a minute [2].

A tag that moves can hand you code nobody on your team read. A tag that stopped moving leaves you on a line nobody maintains. Two different failures share one syntax, and dependency-review-action is the second kind: the v3 tag was never advanced past v3's last patch, so a workflow on @v3 quietly sits on an unmaintained line [12]. A SHA pin holds that position steady. The diagnosis comes from the release list. The recommended target is v5.0.0, at a1d282b36b6f3519aa1f3fc636f609c47dddb294 [27]. The post does not report how many repositories still use @v3.

On sigstore/cosign-installer, the author wrote that the usage is not wrong, but that believing you are on the latest major is a belief a major tag does not support. Only the release list does [14].

I would copy other things out of that post before the pins. The top-level `permissions` block is `contents: read`, widened per job and never at the top [18]. On checkout, `persist-credentials: false` keeps the token out of `.git/config` [19]. Context values such as `github.head_ref` reach the script through `env` instead of being interpolated into the run line [20].

"Pinning is one line of a security posture, and on its own it is the least important line," the author wrote [24].

What to watch

  • Whether the dependency-review-action maintainers advance the v3 tag, retire it, or leave it pointing at v3's last patch.
  • Whether GitHub makes tags immutable for Actions repositories, which would close the moving-tag case without any pinning work.
  • Whether anyone publishes usage counts for @v3 workflows. A count would put a number on the affected population.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories