From fae6c5ca0ed6b2938c6b97c52300133df55ee68e Mon Sep 17 00:00:00 2001 From: Robin Bowes Date: Tue, 11 Aug 2026 16:04:57 +0100 Subject: [PATCH 1/2] fix: pin the runtime image by digest, not tag action.yml referred to ghcr.io/yo61/commitlint-github-action:6.3.0. A tag is mutable, so a consumer pinning this action by commit SHA still ended up resolving a swappable image, which defeats the point of the SHA pin. Refer to the digest published for v6.3.0 instead, and have the release workflow report the digest of what it just pushed so action.yml can be kept in step. --- .github/workflows/publish-image.yml | 19 +++++++++++++++++++ action.yml | 5 ++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-image.yml b/.github/workflows/publish-image.yml index 07e36d63..a23f48fb 100644 --- a/.github/workflows/publish-image.yml +++ b/.github/workflows/publish-image.yml @@ -62,3 +62,22 @@ jobs: echo "published image runs node $node_version" docker run --rm --entrypoint node "$IMAGE:$VERSION" \ -e 'console.log("commitlint " + require("/node_modules/@commitlint/lint/package.json").version)' + + # action.yml pins the image by digest, so every release has to report the + # digest it just published for action.yml to be updated to. + - name: Report digest for action.yml + env: + IMAGE: ghcr.io/${{ github.repository_owner }}/commitlint-github-action + run: | + set -euo pipefail + digest=$(docker image inspect --format '{{index .RepoDigests 0}}' "$IMAGE:$VERSION" | cut -d@ -f2) + echo "published digest: $digest" + { + echo "### Image published" + echo + echo '```' + echo "image: docker://$IMAGE@$digest" + echo '```' + echo + echo "Update \`action.yml\` to this digest if it is not already." + } >> "$GITHUB_STEP_SUMMARY" diff --git a/action.yml b/action.yml index 638d1001..d104016d 100644 --- a/action.yml +++ b/action.yml @@ -36,7 +36,10 @@ outputs: description: The error and warning messages for each one of the analyzed commits runs: using: docker - image: docker://ghcr.io/yo61/commitlint-github-action:6.3.0 + # Pinned by digest, not tag: a tag is mutable, so pinning this action by + # commit SHA downstream would still leave the image swappable. This digest + # is the image published for v6.3.0. + image: docker://ghcr.io/yo61/commitlint-github-action@sha256:78d47699285290a64b68853ca36a6b3554955bda1d4d6c430a843817b0e1940a branding: icon: check-square color: blue From d3656368e37a8a81db1ac252c9b430de5b1d5b95 Mon Sep 17 00:00:00 2001 From: Robin Bowes Date: Tue, 11 Aug 2026 16:08:38 +0100 Subject: [PATCH 2/2] ci: run the action from the published image again The digest in action.yml was not exercised anywhere: the commitlint job rewrites action.yml to build from the Dockerfile, so nothing proved the ghcr.io reference resolves at all. Restore a job that runs the action unmodified. Upstream's version of this pulled a version tag and so failed on every PR that bumped the version, before that image existed; a digest always names an image already published, so it is safe on every push. --- .github/workflows/commitlint.yml | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index af59f344..24389879 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -39,8 +39,24 @@ jobs: RESULTS: ${{ toJSON(steps.run_commitlint.outputs.results) }} run: echo "$RESULTS" - # Upstream also had a `commitlint-pulling-from-docker-hub` job that ran the - # action without rewriting action.yml, so it pulled whichever tag action.yml - # named. That can only pass once the image for that version is published, so - # it fails on every PR that bumps the version. The published image is smoke - # tested in publish-image.yml instead, where it exists. + # Runs the action as consumers do: no rewrite of action.yml, so this pulls + # the pinned digest from ghcr.io. Upstream's equivalent job pulled a version + # tag and so failed on every PR that bumped the version, before the image for + # it existed. A digest always refers to an image already published, so this + # is safe to run on every push and proves the digest reference resolves. + commitlint-from-published-image: + permissions: + contents: read + pull-requests: read + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: '24.19.0' + - run: npm ci --ignore-scripts + - uses: ./ + env: + NODE_PATH: ${{ github.workspace }}/node_modules