From 9df5a07640d640a4ee15d2310caf0049bc0ae790 Mon Sep 17 00:00:00 2001 From: fettpl <38704082+fettpl@users.noreply.github.com> Date: Mon, 16 Feb 2026 17:32:18 +0100 Subject: [PATCH] ci: pin all GitHub Actions to full SHA digests Pin every third-party GitHub Action to its current commit SHA with a version comment, eliminating supply chain risk from mutable version tags. Mutable tags (v4, v2, etc.) can be force-pushed by upstream maintainers; SHA digests are immutable. 18 unique actions pinned across 9 workflow files. Closes #357 Co-Authored-By: Claude Opus 4.6 --- .github/workflows/auto-response.yml | 6 +++--- .github/workflows/ci.yml | 26 +++++++++++++------------- .github/workflows/docker.yml | 16 ++++++++-------- .github/workflows/labeler.yml | 4 ++-- .github/workflows/pr-hygiene.yml | 2 +- .github/workflows/release.yml | 14 +++++++------- .github/workflows/security.yml | 10 +++++----- .github/workflows/stale.yml | 2 +- .github/workflows/workflow-sanity.yml | 6 +++--- 9 files changed, 43 insertions(+), 43 deletions(-) diff --git a/.github/workflows/auto-response.yml b/.github/workflows/auto-response.yml index 6abe8eb..ce197a0 100644 --- a/.github/workflows/auto-response.yml +++ b/.github/workflows/auto-response.yml @@ -20,7 +20,7 @@ jobs: issues: write steps: - name: Apply contributor tier label for issue author - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: | const owner = context.repo.owner; @@ -125,7 +125,7 @@ jobs: pull-requests: write steps: - name: Greet first-time contributors - uses: actions/first-interaction@v1 + uses: actions/first-interaction@2ec0f0fd78838633cd1c1342e4536d49ef72be54 # v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} issue-message: | @@ -156,7 +156,7 @@ jobs: pull-requests: write steps: - name: Handle label-driven responses - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: | const label = context.payload.label?.name; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7b54ad..17a9b7a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: rust_changed: ${{ steps.scope.outputs.rust_changed }} docs_files: ${{ steps.scope.outputs.docs_files }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 @@ -121,14 +121,14 @@ jobs: runs-on: ${{ github.event_name == 'push' && fromJSON('["self-hosted","Linux","X64","lxc-ci"]') || 'ubuntu-latest' }} timeout-minutes: 20 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable with: toolchain: 1.92 components: rustfmt, clippy - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2 - name: Run rustfmt run: cargo fmt --all -- --check - name: Run clippy @@ -141,11 +141,11 @@ jobs: runs-on: ${{ github.event_name == 'push' && fromJSON('["self-hosted","Linux","X64","lxc-ci"]') || 'ubuntu-latest' }} timeout-minutes: 30 steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable with: toolchain: 1.92 - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2 - name: Run tests run: cargo test --locked --verbose @@ -157,11 +157,11 @@ jobs: timeout-minutes: 20 steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable with: toolchain: 1.92 - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2 - name: Build release binary run: cargo build --release --locked --verbose @@ -190,15 +190,15 @@ jobs: runs-on: ${{ github.event_name == 'push' && fromJSON('["self-hosted","Linux","X64","lxc-ci"]') || 'ubuntu-latest' }} timeout-minutes: 15 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Markdown lint - uses: DavidAnson/markdownlint-cli2-action@v22 + uses: DavidAnson/markdownlint-cli2-action@07035fd053f7be764496c0f8d8f9f41f98305101 # v22 with: globs: ${{ needs.changes.outputs.docs_files }} - name: Link check (offline) - uses: lycheeverse/lychee-action@v2 + uses: lycheeverse/lychee-action@a8c4c7cb88f0c7386610c35eb25108e448569cb0 # v2 with: fail: true args: >- diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ec37a37..271274b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -32,21 +32,21 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - name: Extract metadata (tags, labels) id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=ref,event=pr - name: Build smoke image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 with: context: . push: false @@ -69,13 +69,13 @@ jobs: packages: write steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - name: Log in to Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -103,7 +103,7 @@ jobs: echo "tags=${TAGS}" >> "$GITHUB_OUTPUT" - name: Build and push Docker image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 with: context: . push: true diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 9b0a67f..5b37400 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -19,14 +19,14 @@ jobs: timeout-minutes: 10 steps: - name: Apply path labels - uses: actions/labeler@v5 + uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5 continue-on-error: true with: repo-token: ${{ secrets.GITHUB_TOKEN }} sync-labels: true - name: Apply size/risk/module labels - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 continue-on-error: true with: script: | diff --git a/.github/workflows/pr-hygiene.yml b/.github/workflows/pr-hygiene.yml index 543e344..7db9609 100644 --- a/.github/workflows/pr-hygiene.yml +++ b/.github/workflows/pr-hygiene.yml @@ -22,7 +22,7 @@ jobs: STALE_HOURS: "48" steps: - name: Nudge PRs that need rebase or CI refresh - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: | const staleHours = Number(process.env.STALE_HOURS || "48"); diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aa1a475..598468c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,13 +33,13 @@ jobs: artifact: zeroclaw.exe steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable with: targets: ${{ matrix.target }} - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2 - name: Build release run: cargo build --release --locked --target ${{ matrix.target }} @@ -66,7 +66,7 @@ jobs: 7z a ../../../zeroclaw-${{ matrix.target }}.zip ${{ matrix.artifact }} - name: Upload artifact - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: zeroclaw-${{ matrix.target }} path: zeroclaw-${{ matrix.target }}.* @@ -77,15 +77,15 @@ jobs: runs-on: [self-hosted, Linux, X64, lxc-ci] timeout-minutes: 15 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Download all artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: path: artifacts - name: Create GitHub Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2 with: generate_release_notes: true files: artifacts/**/* diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index bff64dc..c3abc10 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -24,10 +24,10 @@ jobs: runs-on: ${{ github.event_name != 'pull_request' && fromJSON('["self-hosted","Linux","X64","lxc-ci"]') || 'ubuntu-latest' }} timeout-minutes: 20 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 + - uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable + - uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2 - name: Install cargo-audit run: cargo install --locked cargo-audit --version 0.22.1 @@ -40,8 +40,8 @@ jobs: runs-on: ${{ github.event_name != 'pull_request' && fromJSON('["self-hosted","Linux","X64","lxc-ci"]') || 'ubuntu-latest' }} timeout-minutes: 20 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - uses: EmbarkStudios/cargo-deny-action@v2 + - uses: EmbarkStudios/cargo-deny-action@3fd3802e88374d3fe9159b834c7714ec57d6c979 # v2 with: command: check advisories licenses sources diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 68687dd..f532229 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Mark stale issues and pull requests - uses: actions/stale@v9 + uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-issue-stale: 21 diff --git a/.github/workflows/workflow-sanity.yml b/.github/workflows/workflow-sanity.yml index c37c1f9..e16df72 100644 --- a/.github/workflows/workflow-sanity.yml +++ b/.github/workflows/workflow-sanity.yml @@ -26,7 +26,7 @@ jobs: timeout-minutes: 10 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Fail on tabs in workflow files shell: bash @@ -59,7 +59,7 @@ jobs: timeout-minutes: 10 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Lint GitHub workflows - uses: rhysd/actionlint@v1.7.11 + uses: rhysd/actionlint@393031adb9afb225ee52ae2ccd7a5af5525e03e8 # v1.7.11