Skip to content

chore: pin GitHub Actions to commit SHAs#97

Merged
tehw0lf merged 2 commits into
mainfrom
chore/pin-action-shas
Jun 30, 2026
Merged

chore: pin GitHub Actions to commit SHAs#97
tehw0lf merged 2 commits into
mainfrom
chore/pin-action-shas

Conversation

@tehw0lf

@tehw0lf tehw0lf commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • Replaces all mutable version tag references (@v7, @v0, @v0.4.1, etc.) in .github/workflows/*.yml with full 40-character commit SHAs, eliminating the supply-chain risk of a tag being re-pointed to different code after review.
  • Each action is bumped to its latest available release before pinning (e.g. actions/cache@v6 → latest v6.1.0, softwareforgood/check-artifact-v4-existence@v0.4.1 → latest v0.4.3).
  • The resolved version is kept as a trailing # vX.Y.Z comment for readability and future maintenance (Dependabot can still track these).
  • All SHAs were resolved live via gh api repos/<owner>/<repo>/git/ref/tags/<tag> (dereferencing annotated tag objects to their underlying commit where needed) and verified to be exactly 40 hex characters before being written.
  • One non-obvious case: rust-lang/crates-io-auth-action@v1 has no v1 tagv1 is a moving branch. Resolved it to the tip of that branch's current commit (matching v1.0.5, its latest tagged release) and pinned to that SHA.

Test plan

  • actionlint .github/workflows/*.yml passes with no errors
  • Confirmed no remaining mutable @vX / @vX.Y.Z references via regex scan (only 40-char SHA refs remain)
  • Confirmed only files under .github/workflows/ were touched
  • Spot-checked diffs across docker, npm, python, android, crates.io, and security-scan workflows for correct SHA/comment formatting

Summary by CodeRabbit

  • Chores
    • Updated multiple automation workflows to pin GitHub Actions to specific commit versions rather than floating release tags.
    • Improves consistency and reduces the risk of unexpected behavior changes during builds, security scans, and release publishing.

Replaces mutable version tags (@v7, @v0, etc.) with full 40-character
commit SHAs to harden against supply chain attacks via tag mutation.
Each action is also bumped to its latest available release before
pinning. The original version is kept as a trailing comment for
readability.
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4f291e26-6326-4c20-b456-2e7074b901d2

📥 Commits

Reviewing files that changed from the base of the PR and between 9fc8398 and 87093cf.

📒 Files selected for processing (13)
  • .github/workflows/lighthouse-scan.yml
  • .github/workflows/lint.yml
  • .github/workflows/post-publish-verification.yml
  • .github/workflows/publish-crates-io.yml
  • .github/workflows/publish-docker-image.yml
  • .github/workflows/publish-firefox-extension.yml
  • .github/workflows/publish-npm-libraries.yml
  • .github/workflows/publish-python-libraries.yml
  • .github/workflows/release-github.yml
  • .github/workflows/security-scan-artifacts.yml
  • .github/workflows/security-scan-dast.yml
  • .github/workflows/security-scan-source.yml
  • .github/workflows/test-and-build.yml
✅ Files skipped from review due to trivial changes (2)
  • .github/workflows/lighthouse-scan.yml
  • .github/workflows/security-scan-source.yml
🚧 Files skipped from review as they are similar to previous changes (10)
  • .github/workflows/lint.yml
  • .github/workflows/publish-npm-libraries.yml
  • .github/workflows/publish-docker-image.yml
  • .github/workflows/release-github.yml
  • .github/workflows/publish-firefox-extension.yml
  • .github/workflows/publish-python-libraries.yml
  • .github/workflows/security-scan-artifacts.yml
  • .github/workflows/security-scan-dast.yml
  • .github/workflows/publish-crates-io.yml
  • .github/workflows/test-and-build.yml

📝 Walkthrough

Walkthrough

This PR pins GitHub Actions references to specific commit SHAs across workflow files, and updates one Firefox packaging step to pass the XPI path through an environment variable before zipping.

Changes

Action SHA pinning across workflows

Layer / File(s) Summary
Checkout and setup pinning
.github/workflows/lighthouse-scan.yml, .github/workflows/lint.yml, .github/workflows/npm-audit-autofix.yml, .github/workflows/set-git-tag.yml, .github/workflows/publish-npm-libraries.yml, .github/workflows/publish-python-libraries.yml
Pins checkout and setup actions used in lightweight, publish-prep, and tagging workflows.
Publish and release action pinning
.github/workflows/publish-crates-io.yml, .github/workflows/publish-docker-image.yml, .github/workflows/publish-firefox-extension.yml, .github/workflows/release-android-apk.yml, .github/workflows/release-github.yml, .github/workflows/post-publish-verification.yml
Pins artifact, Docker, release, cache, and Firefox publish actions; the Firefox package step now uses XPI_PATH for zip.
Security scan workflow pinning
.github/workflows/security-scan-artifacts.yml, .github/workflows/security-scan-dast.yml, .github/workflows/security-scan-source.yml
Pins checkout, scanner, upload, cache, and setup actions in artifact, DAST, and source scan workflows.
Test-and-build pinning
.github/workflows/test-and-build.yml
Pins checkout, cache, language setup, NX SHA, attestation, and artifact upload steps.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • tehw0lf/workflows#81: Both PRs modify .github/workflows/security-scan-dast.yml, including ZAP action references and checkout configuration.
  • tehw0lf/workflows#89: Both PRs touch .github/workflows/lighthouse-scan.yml and its Lighthouse action reference.

Poem

A rabbit hopped through YAML rows,
Pinning tags where the workflow goes.
SHA by SHA, the paths are set,
With whiskers curled around each commit. 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: pinning GitHub Actions to commit SHAs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/pin-action-shas

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/security-scan-artifacts.yml (1)

98-104: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

github/codeql-action/upload-sarif@v4 was left unpinned while every other action in this file was pinned to a SHA.

The PR objective states the test plan includes "regex verification that only SHA references remain," but upload-sarif at lines 100, 120, and 201 still uses the floating @v4 tag. This breaks the consistency of the supply-chain hardening this PR is meant to deliver across the workflow.

Also applies to: 118-124, 199-205

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/security-scan-artifacts.yml around lines 98 - 104, The
upload-sarif steps are still using the floating
github/codeql-action/upload-sarif@v4 tag, which breaks the SHA-only pinning
requirement in this workflow. Update every upload-sarif usage in
security-scan-artifacts.yml to reference the same pinned commit SHA pattern used
by the other actions, keeping the existing step names and with-blocks unchanged.
.github/workflows/security-scan-source.yml (1)

136-141: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

github/codeql-action/upload-sarif@v4 remains unpinned, breaking the stated "only SHA references remain" goal.

Same gap as in security-scan-artifacts.yml: every other uses: in this file (checkout, setup-python, pip-audit, setup-node, upload-artifact) was pinned to a commit SHA, but this step at line 138 still floats on @v4.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/security-scan-source.yml around lines 136 - 141, The
upload-sarif step in the security scan workflow is still using a floating tag
instead of a commit SHA, which violates the pinning policy. Update the
github/codeql-action/upload-sarif@v4 reference in the upload semgrep SARIF step
to the appropriate pinned SHA, matching the style already used by the other
actions in this workflow.
🧹 Nitpick comments (7)
.github/workflows/release-android-apk.yml (2)

172-172: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Optional: softprops/action-gh-release could be replaced with gh release script step.

zizmor's superfluous-actions hint notes this functionality is already available via the gh CLI bundled on GitHub-hosted runners, avoiding a third-party action dependency. Not required for this PR's pinning scope.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-android-apk.yml at line 172, The release workflow
currently uses the third-party softprops/action-gh-release step for publishing
the APK; consider replacing that action usage with an equivalent gh release CLI
step in the release-android-apk workflow. Update the release job to use the
built-in gh command on GitHub-hosted runners while preserving the existing
release behavior and inputs from the current release step.

Source: Linters/SAST tools


68-68: 🔒 Security & Privacy | 🔵 Trivial

Caching steps flagged for cache-poisoning exposure (pre-existing, unrelated to this PR).

zizmor flags both the actions/setup-node cache and the actions/cache keystore-caching step as enabling caching by default (cache-poisoning), which is relevant since this job has write permissions (contents: write, actions: write). Worth a follow-up to scope cache keys tightly (e.g., per-branch/per-ref) or restrict cache restore to trusted refs.

Also applies to: 80-80

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-android-apk.yml at line 68, The Android release
workflow has cache-poisoning exposure because trusted write-capable jobs are
using broad caching via actions/setup-node and the keystore cache step. Update
the release-android-apk job to either disable default caching in setup-node or
scope cache keys/restore conditions tightly (for example by branch or trusted
ref), and review the keystore cache so it only restores for trusted refs. Use
the actions/setup-node step and the keystore-caching step in this workflow to
locate the changes.

Source: Linters/SAST tools

.github/workflows/publish-crates-io.yml (1)

50-50: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Checkout step persists GitHub credentials in local git config.

actions/checkout defaults to persist-credentials: true, leaving the GITHUB_TOKEN in the git config for the rest of the job. Combined with id-token: write permission in this job, an unrelated compromised step later in the job could exfiltrate the token. Static analysis (zizmor) flags this as artipacked.

🔒 Proposed fix
       - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
+        with:
+          persist-credentials: false

This same pattern recurs in publish-docker-image.yml, publish-firefox-extension.yml, publish-npm-libraries.yml, publish-python-libraries.yml, and release-android-apk.yml.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish-crates-io.yml at line 50, The checkout step in the
publish/release workflows is leaving GitHub credentials in the local git config
because actions/checkout is using its default credential persistence. Update the
checkout invocation to disable persisted credentials with persist-credentials
set to false in the affected workflow files, including publish-crates-io and the
other matching publish/release workflows, so later steps cannot reuse the token.

Source: Linters/SAST tools

.github/workflows/test-and-build.yml (1)

122-125: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider setting persist-credentials: false on checkout.

Static analysis (zizmor) flags that this actions/checkout step doesn't set persist-credentials: false, which leaves the GITHUB_TOKEN persisted in the local git config for the remainder of the job. Given this PR's entire purpose is supply-chain hardening, and this job later runs untrusted dependency installs (npm ci, cargo, etc.) and uploads artifacts, persisting credentials increases the blast radius if any subsequent step is compromised.

🔒 Suggested fix
       - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
         with:
           fetch-depth: 0
+          persist-credentials: false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/test-and-build.yml around lines 122 - 125, The checkout
step in the workflow is persisting the default GitHub credentials, which
broadens risk for later untrusted build steps. Update the existing
actions/checkout usage in the test-and-build workflow to set persist-credentials
to false so the GITHUB_TOKEN is not left in local git config; keep the change
within the checkout step identified by actions/checkout.

Source: Linters/SAST tools

.github/workflows/security-scan-source.yml (1)

84-90: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Checkout step persists credentials by default.

Same artipacked finding flagged by zizmor here. This job runs Semgrep/Bandit/pip-audit against repo contents and doesn't need the token to persist for the whole job.

🔒 Suggested fix
       - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
         with:
           fetch-depth: 0
+          persist-credentials: false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/security-scan-source.yml around lines 84 - 90, The
checkout step is persisting Git credentials unnecessarily in the security-scan
workflow. Update the existing actions/checkout step in security-scan-source.yml
to disable credential persistence so the job can still fetch the repo for
Semgrep/Bandit/pip-audit without leaving the token available for the rest of the
workflow.

Source: Linters/SAST tools

.github/workflows/security-scan-artifacts.yml (1)

64-79: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Checkout step still persists credentials by default.

zizmor flags this checkout step for the artipacked issue: the default persist-credentials: true leaves the GITHUB_TOKEN on disk for the remainder of the job, including untrusted steps (e.g. scanning third-party artifacts). Since this job only needs to read the repo for context, set persist-credentials: false.

🔒 Suggested fix
       - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
         with:
           fetch-depth: 0
+          persist-credentials: false

As per the workflows' "minimal permissions principle" guideline, credential exposure should be limited to what each job actually requires.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/security-scan-artifacts.yml around lines 64 - 79, The
checkout step in this workflow is leaving credentials persisted on disk by
default, which is unnecessary for this read-only context. Update the
actions/checkout step in the security-scan-artifacts job to explicitly disable
credential persistence by setting persist-credentials to false, keeping the rest
of the artifact-check and download flow unchanged.

Sources: Coding guidelines, Linters/SAST tools

.github/workflows/security-scan-dast.yml (1)

56-58: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Checkout step persists credentials by default.

Same artipacked finding as the other scan workflows: persist-credentials: false should be set since this job doesn't need to push or use the token beyond initial checkout.

🔒 Suggested fix
       - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
         with:
           fetch-depth: 0
+          persist-credentials: false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/security-scan-dast.yml around lines 56 - 58, The checkout
step is leaving credentials available by default in this scan workflow, which is
unnecessary for a read-only job. Update the actions/checkout step in the
security scan workflow to set persist-credentials to false alongside the
existing fetch-depth setting so the token is not retained after checkout.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/lighthouse-scan.yml:
- Line 56: The checkout step currently leaves the GitHub token persisted in git
config, which is unnecessary for the subsequent Lighthouse action. Update the
actions/checkout invocation in the lighthouse scan workflow to disable
credential persistence by setting persist-credentials to false, keeping the
existing checkout reference and locating it via the checkout step in the
workflow.

In @.github/workflows/lint.yml:
- Line 39: The checkout step in the lint workflow is persisting credentials
unnecessarily; update the actions/checkout usage in the workflow to disable
credential persistence. Since this job only needs the repo contents and the Gist
update uses a separate token, keep the checkout token out of git config by
setting the appropriate checkout option on the existing checkout step in
lint.yml.

In @.github/workflows/publish-firefox-extension.yml:
- Around line 47-48: The packaging step in the Firefox publish workflow is
vulnerable because `inputs.xpi_path` is expanded directly inside the shell
command in `package firefox extension`. Harden `run` by moving the input into an
environment variable for that step and referencing the variable in the `zip`
invocation instead of interpolating the template expression inline. Keep the fix
localized to the workflow job and the `package firefox extension` step so the
path value is treated as data, not shell syntax.

---

Outside diff comments:
In @.github/workflows/security-scan-artifacts.yml:
- Around line 98-104: The upload-sarif steps are still using the floating
github/codeql-action/upload-sarif@v4 tag, which breaks the SHA-only pinning
requirement in this workflow. Update every upload-sarif usage in
security-scan-artifacts.yml to reference the same pinned commit SHA pattern used
by the other actions, keeping the existing step names and with-blocks unchanged.

In @.github/workflows/security-scan-source.yml:
- Around line 136-141: The upload-sarif step in the security scan workflow is
still using a floating tag instead of a commit SHA, which violates the pinning
policy. Update the github/codeql-action/upload-sarif@v4 reference in the upload
semgrep SARIF step to the appropriate pinned SHA, matching the style already
used by the other actions in this workflow.

---

Nitpick comments:
In @.github/workflows/publish-crates-io.yml:
- Line 50: The checkout step in the publish/release workflows is leaving GitHub
credentials in the local git config because actions/checkout is using its
default credential persistence. Update the checkout invocation to disable
persisted credentials with persist-credentials set to false in the affected
workflow files, including publish-crates-io and the other matching
publish/release workflows, so later steps cannot reuse the token.

In @.github/workflows/release-android-apk.yml:
- Line 172: The release workflow currently uses the third-party
softprops/action-gh-release step for publishing the APK; consider replacing that
action usage with an equivalent gh release CLI step in the release-android-apk
workflow. Update the release job to use the built-in gh command on GitHub-hosted
runners while preserving the existing release behavior and inputs from the
current release step.
- Line 68: The Android release workflow has cache-poisoning exposure because
trusted write-capable jobs are using broad caching via actions/setup-node and
the keystore cache step. Update the release-android-apk job to either disable
default caching in setup-node or scope cache keys/restore conditions tightly
(for example by branch or trusted ref), and review the keystore cache so it only
restores for trusted refs. Use the actions/setup-node step and the
keystore-caching step in this workflow to locate the changes.

In @.github/workflows/security-scan-artifacts.yml:
- Around line 64-79: The checkout step in this workflow is leaving credentials
persisted on disk by default, which is unnecessary for this read-only context.
Update the actions/checkout step in the security-scan-artifacts job to
explicitly disable credential persistence by setting persist-credentials to
false, keeping the rest of the artifact-check and download flow unchanged.

In @.github/workflows/security-scan-dast.yml:
- Around line 56-58: The checkout step is leaving credentials available by
default in this scan workflow, which is unnecessary for a read-only job. Update
the actions/checkout step in the security scan workflow to set
persist-credentials to false alongside the existing fetch-depth setting so the
token is not retained after checkout.

In @.github/workflows/security-scan-source.yml:
- Around line 84-90: The checkout step is persisting Git credentials
unnecessarily in the security-scan workflow. Update the existing
actions/checkout step in security-scan-source.yml to disable credential
persistence so the job can still fetch the repo for Semgrep/Bandit/pip-audit
without leaving the token available for the rest of the workflow.

In @.github/workflows/test-and-build.yml:
- Around line 122-125: The checkout step in the workflow is persisting the
default GitHub credentials, which broadens risk for later untrusted build steps.
Update the existing actions/checkout usage in the test-and-build workflow to set
persist-credentials to false so the GITHUB_TOKEN is not left in local git
config; keep the change within the checkout step identified by actions/checkout.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 88c3c82a-2f39-40d1-87fa-22ed13574e14

📥 Commits

Reviewing files that changed from the base of the PR and between 912443e and 9fc8398.

📒 Files selected for processing (16)
  • .github/workflows/lighthouse-scan.yml
  • .github/workflows/lint.yml
  • .github/workflows/npm-audit-autofix.yml
  • .github/workflows/post-publish-verification.yml
  • .github/workflows/publish-crates-io.yml
  • .github/workflows/publish-docker-image.yml
  • .github/workflows/publish-firefox-extension.yml
  • .github/workflows/publish-npm-libraries.yml
  • .github/workflows/publish-python-libraries.yml
  • .github/workflows/release-android-apk.yml
  • .github/workflows/release-github.yml
  • .github/workflows/security-scan-artifacts.yml
  • .github/workflows/security-scan-dast.yml
  • .github/workflows/security-scan-source.yml
  • .github/workflows/set-git-tag.yml
  • .github/workflows/test-and-build.yml

Comment thread .github/workflows/lighthouse-scan.yml
Comment thread .github/workflows/lint.yml
Comment thread .github/workflows/publish-firefox-extension.yml Outdated
… review

- Pin github/codeql-action/upload-sarif@v4 (missed by the original regex
  scan since it has a multi-segment path) to its commit SHA in
  security-scan-source.yml, security-scan-artifacts.yml, and
  post-publish-verification.yml.
- Set persist-credentials: false on actions/checkout in jobs that don't
  perform a raw git push, reducing the blast radius if a later step in
  the job is compromised. Left untouched in npm-audit-autofix.yml,
  release-android-apk.yml, and set-git-tag.yml, which rely on the
  persisted token for git commit/tag/push.
- Fix a pre-existing shell injection in publish-firefox-extension.yml by
  passing inputs.xpi_path through an env var instead of interpolating it
  directly into the zip command.
@tehw0lf tehw0lf merged commit 685fea9 into main Jun 30, 2026
2 of 3 checks passed
@tehw0lf tehw0lf deleted the chore/pin-action-shas branch June 30, 2026 22:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant