From 5720de404d6619337cf9baf6c178b2234eb913b0 Mon Sep 17 00:00:00 2001 From: Cameron G Date: Sat, 20 Jun 2026 05:57:02 +0000 Subject: [PATCH] ci: pin third-party actions to commit SHA (supply-chain hardening) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pins all GitHub Actions references in .github/workflows/ to a full 40-character commit SHA, with the original tag preserved as a trailing comment. This protects CI from a compromised tag — the same class of attack used in the tj-actions/changed-files compromise (CVE-2025-30066, March 2025), where a malicious commit was force-pushed to a mutable tag and stole secrets from every workflow that consumed it. GitHub's own hardening guidance recommends pinning third-party actions to a full commit SHA for exactly this reason: https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-third-party-actions Scope: - claude.yml : 2 pins - python.yml : 10 pins - readme-pr-check.yml: 2 pins - release.yml : 13 pins - typescript.yml : 7 pins Total: 34 references across 5 workflows, 10 unique actions. All pinned SHAs resolved from the tag's current commit object via the GitHub REST API on 2026-06-20. No behavior change: SHAs were resolved from the same refs the workflows currently use (e.g. @v6 → SHA of v6 tag's commit). Dependabot can still bump these — it understands the 'SHA + trailing version comment' pattern and will open PRs to update to the next SHA when a new tag is published. --- .github/workflows/claude.yml | 4 ++-- .github/workflows/python.yml | 20 ++++++++++---------- .github/workflows/readme-pr-check.yml | 4 ++-- .github/workflows/release.yml | 26 +++++++++++++------------- .github/workflows/typescript.yml | 14 +++++++------- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 92c74fceba..3ba027ce0f 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -26,13 +26,13 @@ jobs: actions: read steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: fetch-depth: 1 - name: Run Claude Code id: claude - uses: anthropics/claude-code-action@v1 + uses: anthropics/claude-code-action@51705da45eecce209d4700538bf8377d5b5fc695 # v1 with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index df84276249..3e2efb6fb8 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -14,7 +14,7 @@ jobs: outputs: packages: ${{ steps.find-packages.outputs.packages }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - name: Find Python packages id: find-packages @@ -31,13 +31,13 @@ jobs: name: Test ${{ matrix.package }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - name: Install uv - uses: astral-sh/setup-uv@v3 + uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3 - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version-file: "src/${{ matrix.package }}/.python-version" @@ -68,13 +68,13 @@ jobs: name: Build ${{ matrix.package }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - name: Install uv - uses: astral-sh/setup-uv@v3 + uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3 - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version-file: "src/${{ matrix.package }}/.python-version" @@ -91,7 +91,7 @@ jobs: run: uv build - name: Upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: dist-${{ matrix.package }} path: src/${{ matrix.package }}/dist/ @@ -112,10 +112,10 @@ jobs: steps: - name: Download artifacts - uses: actions/download-artifact@v7 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 with: name: dist-${{ matrix.package }} path: dist/ - name: Publish package to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1 diff --git a/.github/workflows/readme-pr-check.yml b/.github/workflows/readme-pr-check.yml index 66cb3a31e6..1cabb1eee2 100644 --- a/.github/workflows/readme-pr-check.yml +++ b/.github/workflows/readme-pr-check.yml @@ -17,7 +17,7 @@ jobs: pull-requests: write steps: - name: Check files and comment if README-only - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: | const { owner, repo } = context.repo; @@ -63,7 +63,7 @@ jobs: pull-requests: write steps: - name: Swap labels and minimize comments - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: | const { owner, repo } = context.repo; diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a3ad5387d3..edeba25d77 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: npm_packages: ${{ steps.create-npm-packages.outputs.npm_packages}} pypi_packages: ${{ steps.create-pypi-packages.outputs.pypi_packages}} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: fetch-depth: 0 @@ -27,7 +27,7 @@ jobs: echo "Using last release hash: ${HASH}" - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5 - name: Create version name id: create-version @@ -43,7 +43,7 @@ jobs: cat RELEASE_NOTES.md - name: Release notes - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: release-notes path: RELEASE_NOTES.md @@ -74,12 +74,12 @@ jobs: outputs: changes_made: ${{ steps.commit.outputs.changes_made }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: fetch-depth: 0 - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5 - name: Update packages run: | @@ -118,15 +118,15 @@ jobs: id-token: write # Required for trusted publishing runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: ref: ${{ needs.create-metadata.outputs.version }} - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5 - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version-file: "src/${{ matrix.package }}/.python-version" @@ -143,7 +143,7 @@ jobs: run: uv build - name: Publish package to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1 with: packages-dir: src/${{ matrix.package }}/dist @@ -158,11 +158,11 @@ jobs: environment: release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: ref: ${{ needs.create-metadata.outputs.version }} - - uses: actions/setup-node@v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 cache: npm @@ -204,10 +204,10 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - name: Download release notes - uses: actions/download-artifact@v7 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 with: name: release-notes diff --git a/.github/workflows/typescript.yml b/.github/workflows/typescript.yml index 4e29e524ad..33fc6d5499 100644 --- a/.github/workflows/typescript.yml +++ b/.github/workflows/typescript.yml @@ -14,7 +14,7 @@ jobs: outputs: packages: ${{ steps.find-packages.outputs.packages }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - name: Find JS packages id: find-packages working-directory: src @@ -30,9 +30,9 @@ jobs: name: Test ${{ matrix.package }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 cache: npm @@ -53,9 +53,9 @@ jobs: name: Build ${{ matrix.package }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 cache: npm @@ -84,8 +84,8 @@ jobs: id-token: write steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 cache: npm