From 9fc83989873b74e88e4552648aaefadb58af4bc1 Mon Sep 17 00:00:00 2001 From: tehw0lf Date: Wed, 1 Jul 2026 00:20:56 +0200 Subject: [PATCH 1/2] chore: pin GitHub Actions to commit SHAs and bump to latest versions 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. --- .github/workflows/lighthouse-scan.yml | 4 +-- .github/workflows/lint.yml | 2 +- .github/workflows/npm-audit-autofix.yml | 4 +-- .../workflows/post-publish-verification.yml | 6 ++--- .github/workflows/publish-crates-io.yml | 10 +++---- .github/workflows/publish-docker-image.yml | 12 ++++----- .../workflows/publish-firefox-extension.yml | 4 +-- .github/workflows/publish-npm-libraries.yml | 8 +++--- .../workflows/publish-python-libraries.yml | 4 +-- .github/workflows/release-android-apk.yml | 20 +++++++------- .github/workflows/release-github.yml | 8 +++--- .github/workflows/security-scan-artifacts.yml | 18 ++++++------- .github/workflows/security-scan-dast.yml | 8 +++--- .github/workflows/security-scan-source.yml | 10 +++---- .github/workflows/set-git-tag.yml | 2 +- .github/workflows/test-and-build.yml | 26 +++++++++---------- 16 files changed, 73 insertions(+), 73 deletions(-) diff --git a/.github/workflows/lighthouse-scan.yml b/.github/workflows/lighthouse-scan.yml index a0d1942..177f4b4 100644 --- a/.github/workflows/lighthouse-scan.yml +++ b/.github/workflows/lighthouse-scan.yml @@ -53,7 +53,7 @@ jobs: outputs: lighthouse_result: ${{ steps.audit.outcome }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: write lighthouserc run: | @@ -102,7 +102,7 @@ jobs: - name: run lighthouse id: audit - uses: treosh/lighthouse-ci-action@v12 + uses: treosh/lighthouse-ci-action@3e7e23fb74242897f95c0ba9cabad3d0227b9b18 # 12.6.2 with: urls: ${{ steps.urls.outputs.urls }} configPath: .lighthouserc.json diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f14a65c..d271bd5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -36,7 +36,7 @@ jobs: fi - name: Checkout workflow repository - uses: actions/checkout@v7 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: repository: tehw0lf/workflows ref: ${{ steps.context.outputs.workflows_ref }} diff --git a/.github/workflows/npm-audit-autofix.yml b/.github/workflows/npm-audit-autofix.yml index 7817ca8..d696085 100644 --- a/.github/workflows/npm-audit-autofix.yml +++ b/.github/workflows/npm-audit-autofix.yml @@ -71,14 +71,14 @@ jobs: fi - name: checkout - uses: actions/checkout@v7 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ inputs.head_ref }} token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 - name: setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ inputs.node_version }} cache: "npm" diff --git a/.github/workflows/post-publish-verification.yml b/.github/workflows/post-publish-verification.yml index a950ea0..e400989 100644 --- a/.github/workflows/post-publish-verification.yml +++ b/.github/workflows/post-publish-verification.yml @@ -58,7 +58,7 @@ jobs: # Authenticate to GHCR for pulling images - name: log in to GitHub Container Registry if: ${{ inputs.registry == 'ghcr.io' && inputs.docker_meta != '' }} - uses: docker/login-action@v4 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -68,7 +68,7 @@ jobs: - name: cache trivy installation id: cache-trivy if: ${{ inputs.docker_meta != '' }} - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | /usr/local/bin/trivy @@ -143,7 +143,7 @@ jobs: # Upload scan reports as artifacts - name: upload security scan reports if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: post-publish-verification-reports path: trivy-image-*.sarif diff --git a/.github/workflows/publish-crates-io.yml b/.github/workflows/publish-crates-io.yml index c9f083f..2e2048d 100644 --- a/.github/workflows/publish-crates-io.yml +++ b/.github/workflows/publish-crates-io.yml @@ -47,10 +47,10 @@ jobs: run: working-directory: ${{ inputs.root_dir }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: check build artifact existence - uses: softwareforgood/check-artifact-v4-existence@v0 + uses: softwareforgood/check-artifact-v4-existence@f988c59be23773bdf226dffa5720d85a13501fba # v0.4.3 id: check_artifact_exists with: name: build @@ -66,7 +66,7 @@ jobs: - name: download build artifact if: ${{ inputs.artifact_path != '' && steps.check_artifact_exists.outputs.exists == 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: build path: ${{ inputs.artifact_path }} @@ -75,7 +75,7 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: cache cargo dependencies - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry @@ -124,7 +124,7 @@ jobs: - name: authenticate with crates.io if: ${{ steps.version_check.outputs.already_published == 'false' }} id: auth - uses: rust-lang/crates-io-auth-action@v1 + uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5 - name: cargo publish dry-run if: ${{ inputs.dry_run == true && steps.version_check.outputs.already_published == 'false' }} diff --git a/.github/workflows/publish-docker-image.yml b/.github/workflows/publish-docker-image.yml index 09c6644..b3f551c 100644 --- a/.github/workflows/publish-docker-image.yml +++ b/.github/workflows/publish-docker-image.yml @@ -66,7 +66,7 @@ jobs: matrix: docker: ${{ fromJson(inputs.docker_meta) }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: validate docker metadata if: ${{ inputs.docker_meta != '' }} @@ -82,14 +82,14 @@ jobs: shell: bash - name: check build artifact existence - uses: softwareforgood/check-artifact-v4-existence@v0 + uses: softwareforgood/check-artifact-v4-existence@f988c59be23773bdf226dffa5720d85a13501fba # v0.4.3 id: check_artifact_exists with: name: build - name: download build artifact if: ${{ inputs.artifact_path != '' && steps.check_artifact_exists.outputs.exists == 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: build path: ${{ inputs.artifact_path }} @@ -120,11 +120,11 @@ jobs: - name: set up docker if: ${{ inputs.artifact_path == '' || steps.check_artifact_exists.outputs.exists == 'true' }} - uses: docker/setup-buildx-action@v4.1.0 + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 - name: login if: ${{ inputs.artifact_path == '' || steps.check_artifact_exists.outputs.exists == 'true' }} - uses: docker/login-action@v4 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: registry: ${{ inputs.registry }} username: ${{ github.actor }} @@ -140,7 +140,7 @@ jobs: - name: build and push image if: ${{ inputs.artifact_path == '' || steps.check_artifact_exists.outputs.exists == 'true' }} - uses: docker/build-push-action@v7 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . file: ${{ matrix.docker.file }} diff --git a/.github/workflows/publish-firefox-extension.yml b/.github/workflows/publish-firefox-extension.yml index 58b8b4d..90501b4 100644 --- a/.github/workflows/publish-firefox-extension.yml +++ b/.github/workflows/publish-firefox-extension.yml @@ -42,14 +42,14 @@ jobs: run: working-directory: ${{ inputs.root_dir }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: package firefox extension run: zip -r ${{ inputs.xpi_path }} * -x .git\* -x .github\* shell: bash - name: publish firefox extension - uses: wdzeng/firefox-addon@v1.2.1 + uses: wdzeng/firefox-addon@3184ee491b500e080885e046051366a4228c6e5d # v1.2.1 with: addon-guid: ${{ inputs.addon_guid }} xpi-path: ${{ inputs.xpi_path }} diff --git a/.github/workflows/publish-npm-libraries.yml b/.github/workflows/publish-npm-libraries.yml index 6aae400..e0870f7 100644 --- a/.github/workflows/publish-npm-libraries.yml +++ b/.github/workflows/publish-npm-libraries.yml @@ -52,25 +52,25 @@ jobs: run: working-directory: ${{ inputs.root_dir }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 - name: check build artifact existence - uses: softwareforgood/check-artifact-v4-existence@v0 + uses: softwareforgood/check-artifact-v4-existence@f988c59be23773bdf226dffa5720d85a13501fba # v0.4.3 id: check_artifact_exists with: name: build - name: download build artifact if: ${{ inputs.artifact_path != '' && steps.check_artifact_exists.outputs.exists == 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: build path: ${{ inputs.artifact_path }} - - uses: actions/setup-node@v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 if: ${{ inputs.tool == 'npm' || inputs.tool == 'yarn' }} with: node-version: "24.16.0" diff --git a/.github/workflows/publish-python-libraries.yml b/.github/workflows/publish-python-libraries.yml index 1032f61..77c73e1 100644 --- a/.github/workflows/publish-python-libraries.yml +++ b/.github/workflows/publish-python-libraries.yml @@ -38,10 +38,10 @@ jobs: run: working-directory: ${{ inputs.root_dir }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: check build artifact existence - uses: softwareforgood/check-artifact-v4-existence@v0 + uses: softwareforgood/check-artifact-v4-existence@f988c59be23773bdf226dffa5720d85a13501fba # v0.4.3 id: check_artifact_exists with: name: build diff --git a/.github/workflows/release-android-apk.yml b/.github/workflows/release-android-apk.yml index 8d9a074..c11f12b 100644 --- a/.github/workflows/release-android-apk.yml +++ b/.github/workflows/release-android-apk.yml @@ -37,35 +37,35 @@ jobs: contents: write packages: read steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: check app artifact existence - uses: softwareforgood/check-artifact-v4-existence@v0 + uses: softwareforgood/check-artifact-v4-existence@f988c59be23773bdf226dffa5720d85a13501fba # v0.4.3 id: check_app_artifact_exists with: name: app - name: download app artifact if: ${{ inputs.app_root != '' && steps.check_app_artifact_exists.outputs.exists == 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: app path: ${{ inputs.app_root }} - name: check build artifact existence - uses: softwareforgood/check-artifact-v4-existence@v0 + uses: softwareforgood/check-artifact-v4-existence@f988c59be23773bdf226dffa5720d85a13501fba # v0.4.3 id: check_build_artifact_exists with: name: build - name: download build artifact if: ${{ inputs.artifact_path != '' && steps.check_build_artifact_exists.outputs.exists == 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: build path: ${{ inputs.artifact_path }} - - uses: actions/setup-node@v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 if: ${{ (inputs.tool == 'npm' || inputs.tool == 'yarn') && steps.check_build_artifact_exists.outputs.exists == 'true' && steps.check_app_artifact_exists.outputs.exists == 'true' }} with: node-version: "24.16.0" @@ -77,7 +77,7 @@ jobs: - name: cache keystore if: ${{ steps.check_build_artifact_exists.outputs.exists == 'true' && steps.check_app_artifact_exists.outputs.exists == 'true' }} - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 id: cache with: path: ${{ inputs.app_root }}/android/app/keystore.jks @@ -98,14 +98,14 @@ jobs: - name: set up jdk if: ${{ steps.check_build_artifact_exists.outputs.exists == 'true' && steps.check_app_artifact_exists.outputs.exists == 'true' }} - uses: actions/setup-java@v5 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: "adopt" java-version: "24" - name: set up android sdk if: ${{ steps.check_build_artifact_exists.outputs.exists == 'true' && steps.check_app_artifact_exists.outputs.exists == 'true' }} - uses: android-actions/setup-android@v4 + uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1 with: packages: "build-tools;35.0.0" @@ -169,7 +169,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: softprops/action-gh-release@v3 + - uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1 if: ${{ steps.check_build_artifact_exists.outputs.exists == 'true' && steps.check_app_artifact_exists.outputs.exists == 'true' && steps.check_release_exists.outputs.release_exists != 'true' }} with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-github.yml b/.github/workflows/release-github.yml index 08d8efa..dcb295a 100644 --- a/.github/workflows/release-github.yml +++ b/.github/workflows/release-github.yml @@ -43,17 +43,17 @@ jobs: working-directory: ${{ inputs.root_dir }} steps: - name: checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: check build artifact existence - uses: softwareforgood/check-artifact-v4-existence@v0 + uses: softwareforgood/check-artifact-v4-existence@f988c59be23773bdf226dffa5720d85a13501fba # v0.4.3 id: check_artifact_exists with: name: build - name: download build artifact if: ${{ inputs.artifact_path != '' && steps.check_artifact_exists.outputs.exists == 'true' }} - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: build path: ${{ inputs.artifact_path }} @@ -103,7 +103,7 @@ jobs: if: ${{ inputs.release_pre != '' && steps.check_artifact_exists.outputs.exists == 'true' && steps.check_release_exists.outputs.release_exists != 'true' }} run: ${{ inputs.release_pre }} - - uses: softprops/action-gh-release@v3 + - uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1 if: ${{ steps.check_artifact_exists.outputs.exists == 'true' && steps.check_release_exists.outputs.release_exists != 'true' }} with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/security-scan-artifacts.yml b/.github/workflows/security-scan-artifacts.yml index a63a462..d9d4533 100644 --- a/.github/workflows/security-scan-artifacts.yml +++ b/.github/workflows/security-scan-artifacts.yml @@ -61,7 +61,7 @@ jobs: run: working-directory: ${{ inputs.root_dir }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 @@ -69,14 +69,14 @@ jobs: - name: check if build artifact exists if: ${{ inputs.artifact_path != '' }} id: check-artifact - uses: softwareforgood/check-artifact-v4-existence@v0.4.1 + uses: softwareforgood/check-artifact-v4-existence@f988c59be23773bdf226dffa5720d85a13501fba # v0.4.3 with: name: build # Download build artifacts for scanning - name: download build artifact if: ${{ steps.check-artifact.outputs.exists == 'true' }} - uses: actions/download-artifact@v8.0.1 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: build path: ${{ inputs.artifact_path }} @@ -85,7 +85,7 @@ jobs: - name: trivy filesystem scan id: trivy-fs if: ${{ inputs.artifact_path != '' && steps.check-artifact.outputs.exists == 'true' }} - uses: aquasecurity/trivy-action@v0.36.0 + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: scan-type: "fs" scan-ref: "${{ inputs.artifact_path }}" @@ -107,7 +107,7 @@ jobs: - name: grype filesystem scan id: grype if: ${{ inputs.artifact_path != '' && steps.check-artifact.outputs.exists == 'true' }} - uses: anchore/scan-action@v7.4.0 + uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v7.4.0 with: path: "${{ inputs.artifact_path }}" fail-build: true @@ -133,7 +133,7 @@ jobs: - name: upload security scan reports if: always() - uses: actions/upload-artifact@v7.0.1 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: security-scan-artifact-reports path: | @@ -144,7 +144,7 @@ jobs: - name: cache trivy installation if: ${{ inputs.docker_meta != '' }} id: cache-trivy - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | /usr/local/bin/trivy @@ -160,7 +160,7 @@ jobs: - name: set up docker if: ${{ inputs.docker_meta != '' }} - uses: docker/setup-buildx-action@v4.1.0 + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 - name: build and scan docker images if: ${{ inputs.docker_meta != '' }} @@ -206,7 +206,7 @@ jobs: - name: upload docker scan reports if: always() && steps.docker-scan.outcome != 'skipped' - uses: actions/upload-artifact@v7.0.1 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: docker-scan-reports path: trivy-image-*.sarif diff --git a/.github/workflows/security-scan-dast.yml b/.github/workflows/security-scan-dast.yml index 062339c..2b9e4af 100644 --- a/.github/workflows/security-scan-dast.yml +++ b/.github/workflows/security-scan-dast.yml @@ -53,14 +53,14 @@ jobs: outputs: zap_result: ${{ steps.zap-scan.outcome }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 - name: zap baseline scan id: zap-scan if: ${{ inputs.scan_type == 'baseline' }} - uses: zaproxy/action-baseline@v0.15.0 + uses: zaproxy/action-baseline@de8ad967d3548d44ef623df22cf95c3b0baf8b25 # v0.15.0 with: target: ${{ inputs.target_url }} rules_file_name: ${{ inputs.rules_file }} @@ -72,7 +72,7 @@ jobs: - name: zap full scan id: zap-full-scan if: ${{ inputs.scan_type == 'full' }} - uses: zaproxy/action-full-scan@v0.13.0 + uses: zaproxy/action-full-scan@3c58388149901b9a03b7718852c5ba889646c27c # v0.13.0 with: target: ${{ inputs.target_url }} rules_file_name: ${{ inputs.rules_file }} @@ -83,7 +83,7 @@ jobs: - name: upload zap report if: always() - uses: actions/upload-artifact@v7.0.1 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: zap-dast-report-${{ inputs.scan_type }} path: | diff --git a/.github/workflows/security-scan-source.yml b/.github/workflows/security-scan-source.yml index 1d2b174..197806f 100644 --- a/.github/workflows/security-scan-source.yml +++ b/.github/workflows/security-scan-source.yml @@ -81,13 +81,13 @@ jobs: run: working-directory: ${{ inputs.root_dir }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 # Setup Python once for all tools (Semgrep, Bandit, pip-audit) - name: setup python (from pyproject.toml for uv, 3.14 otherwise) - uses: actions/setup-python@v6 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ inputs.tool == 'uv' && '' || '3.14' }} python-version-file: @@ -156,7 +156,7 @@ jobs: - name: pip-audit dependency scan if: ${{ inputs.tool == 'uv' }} id: pip-audit - uses: pypa/gh-action-pip-audit@v1.1.0 + uses: pypa/gh-action-pip-audit@1220774d901786e6f652ae159f7b6bc8fea6d266 # v1.1.0 with: inputs: ${{ inputs.root_dir }} continue-on-error: false @@ -164,7 +164,7 @@ jobs: # Layer 1c: Node.js-specific scanning - name: setup node for npm scanning if: ${{ inputs.tool == 'npm' || inputs.tool == 'yarn' }} - uses: actions/setup-node@v6 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24.16.0" cache: "${{ inputs.tool }}" @@ -186,7 +186,7 @@ jobs: - name: upload security scan reports if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: security-scan-source-reports path: | diff --git a/.github/workflows/set-git-tag.yml b/.github/workflows/set-git-tag.yml index a9b2b7a..e45dde7 100644 --- a/.github/workflows/set-git-tag.yml +++ b/.github/workflows/set-git-tag.yml @@ -36,7 +36,7 @@ jobs: working-directory: ${{ inputs.root_dir }} steps: - name: checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: extract version from manifest id: extract_version diff --git a/.github/workflows/test-and-build.yml b/.github/workflows/test-and-build.yml index 7b8cc98..ff4d5e7 100644 --- a/.github/workflows/test-and-build.yml +++ b/.github/workflows/test-and-build.yml @@ -119,12 +119,12 @@ jobs: run: working-directory: ${{ inputs.root_dir }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 - name: cache dependencies - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.npm @@ -141,12 +141,12 @@ jobs: - name: configure jdk if: ${{ inputs.tool == './gradlew' || inputs.tool == 'mvn' }} - uses: actions/setup-java@v5 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: "temurin" java-version: "21" - - uses: actions/setup-node@v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 if: ${{ inputs.tool == 'npm' || inputs.tool == 'yarn' }} with: node-version: "24.16.0" @@ -156,13 +156,13 @@ jobs: ${{ inputs.root_dir }}/yarn.lock ${{ inputs.root_dir }}/pnpm-lock.yaml - - uses: astral-sh/setup-uv@v8.2.0 + - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 if: ${{ inputs.tool == 'uv' }} with: enable-cache: true cache-dependency-glob: "${{ inputs.root_dir }}/uv.lock" - - uses: actions/setup-python@v6 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 if: ${{ inputs.tool == 'uv' }} with: python-version-file: "${{ inputs.root_dir }}/pyproject.toml" @@ -176,7 +176,7 @@ jobs: - name: cache cargo dependencies if: ${{ inputs.tool == 'cargo' }} - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry @@ -188,7 +188,7 @@ jobs: - name: enable nx shas if: ${{ success() && hashFiles('./nx.json') != '' }} - uses: nrwl/nx-set-shas@v5 + uses: nrwl/nx-set-shas@afb73a62d26e41464e9254689e1fd6122ee683c1 # v5.0.1 with: main-branch-name: main @@ -239,7 +239,7 @@ jobs: - name: Cache Playwright browsers if: ${{ (inputs.tool == 'npm' || inputs.tool == 'yarn') && inputs.e2e != '' && (hashFiles('**/**/playwright.config.ts') != '' || hashFiles('**/**/playwright.config.js') != '' || hashFiles('**/**/playwright.config.mjs') != '')}} id: playwright-cache - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.cache/ms-playwright key: playwright-${{ runner.os }}-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }} @@ -286,14 +286,14 @@ jobs: - name: attest SBOM if: ${{ inputs.enable_sbom_attestation == 'true' && (inputs.tool == 'npm' || inputs.tool == 'yarn') }} - uses: actions/attest@v4 + uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1 with: subject-path: ${{ inputs.root_dir }}/${{ inputs.artifact_path }} sbom-path: ${{ inputs.root_dir }}/sbom/sbom.cyclonedx.json - name: upload SBOM artifact if: ${{ inputs.enable_sbom_attestation == 'true' && (inputs.tool == 'npm' || inputs.tool == 'yarn') }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: sbom-npm-libraries path: ${{ inputs.root_dir }}/sbom @@ -302,14 +302,14 @@ jobs: - name: upload build artifact (from artifact_path) if: ${{ inputs.artifact_path != '' }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: build path: ${{ inputs.root_dir }}/${{ inputs.artifact_path }} - name: upload app artifact (from app_root) if: ${{ github.event_name == 'push' && inputs.app_root != '' }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: app path: ${{ inputs.app_root }} From 87093cf9cc556939aa3ba1d8a7a88ef123e4224f Mon Sep 17 00:00:00 2001 From: tehw0lf Date: Wed, 1 Jul 2026 00:36:46 +0200 Subject: [PATCH 2/2] fix: pin remaining unpinned action and harden checkout per CodeRabbit 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. --- .github/workflows/lighthouse-scan.yml | 2 ++ .github/workflows/lint.yml | 1 + .github/workflows/post-publish-verification.yml | 2 +- .github/workflows/publish-crates-io.yml | 2 ++ .github/workflows/publish-docker-image.yml | 2 ++ .github/workflows/publish-firefox-extension.yml | 6 +++++- .github/workflows/publish-npm-libraries.yml | 1 + .github/workflows/publish-python-libraries.yml | 2 ++ .github/workflows/release-github.yml | 2 ++ .github/workflows/security-scan-artifacts.yml | 7 ++++--- .github/workflows/security-scan-dast.yml | 1 + .github/workflows/security-scan-source.yml | 3 ++- .github/workflows/test-and-build.yml | 1 + 13 files changed, 26 insertions(+), 6 deletions(-) diff --git a/.github/workflows/lighthouse-scan.yml b/.github/workflows/lighthouse-scan.yml index 177f4b4..d9ba544 100644 --- a/.github/workflows/lighthouse-scan.yml +++ b/.github/workflows/lighthouse-scan.yml @@ -54,6 +54,8 @@ jobs: lighthouse_result: ${{ steps.audit.outcome }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: write lighthouserc run: | diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d271bd5..9310d36 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -41,6 +41,7 @@ jobs: repository: tehw0lf/workflows ref: ${{ steps.context.outputs.workflows_ref }} path: workflows-repo + persist-credentials: false - name: Generate workflow hash for cache key id: workflow-hash diff --git a/.github/workflows/post-publish-verification.yml b/.github/workflows/post-publish-verification.yml index e400989..109fed4 100644 --- a/.github/workflows/post-publish-verification.yml +++ b/.github/workflows/post-publish-verification.yml @@ -134,7 +134,7 @@ jobs: # Upload SARIF results to GitHub Security - name: upload trivy image SARIF if: always() && steps.trivy-image.outcome != 'skipped' - uses: github/codeql-action/upload-sarif@v4 + uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: sarif_file: trivy-image-*.sarif category: trivy-published-images diff --git a/.github/workflows/publish-crates-io.yml b/.github/workflows/publish-crates-io.yml index 2e2048d..b48575a 100644 --- a/.github/workflows/publish-crates-io.yml +++ b/.github/workflows/publish-crates-io.yml @@ -48,6 +48,8 @@ jobs: working-directory: ${{ inputs.root_dir }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: check build artifact existence uses: softwareforgood/check-artifact-v4-existence@f988c59be23773bdf226dffa5720d85a13501fba # v0.4.3 diff --git a/.github/workflows/publish-docker-image.yml b/.github/workflows/publish-docker-image.yml index b3f551c..5962d3a 100644 --- a/.github/workflows/publish-docker-image.yml +++ b/.github/workflows/publish-docker-image.yml @@ -67,6 +67,8 @@ jobs: docker: ${{ fromJson(inputs.docker_meta) }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: validate docker metadata if: ${{ inputs.docker_meta != '' }} diff --git a/.github/workflows/publish-firefox-extension.yml b/.github/workflows/publish-firefox-extension.yml index 90501b4..89da9c1 100644 --- a/.github/workflows/publish-firefox-extension.yml +++ b/.github/workflows/publish-firefox-extension.yml @@ -43,10 +43,14 @@ jobs: working-directory: ${{ inputs.root_dir }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: package firefox extension - run: zip -r ${{ inputs.xpi_path }} * -x .git\* -x .github\* + run: zip -r "$XPI_PATH" * -x .git\* -x .github\* shell: bash + env: + XPI_PATH: ${{ inputs.xpi_path }} - name: publish firefox extension uses: wdzeng/firefox-addon@3184ee491b500e080885e046051366a4228c6e5d # v1.2.1 diff --git a/.github/workflows/publish-npm-libraries.yml b/.github/workflows/publish-npm-libraries.yml index e0870f7..8d00977 100644 --- a/.github/workflows/publish-npm-libraries.yml +++ b/.github/workflows/publish-npm-libraries.yml @@ -56,6 +56,7 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 + persist-credentials: false - name: check build artifact existence uses: softwareforgood/check-artifact-v4-existence@f988c59be23773bdf226dffa5720d85a13501fba # v0.4.3 diff --git a/.github/workflows/publish-python-libraries.yml b/.github/workflows/publish-python-libraries.yml index 77c73e1..5a000f4 100644 --- a/.github/workflows/publish-python-libraries.yml +++ b/.github/workflows/publish-python-libraries.yml @@ -39,6 +39,8 @@ jobs: working-directory: ${{ inputs.root_dir }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: check build artifact existence uses: softwareforgood/check-artifact-v4-existence@f988c59be23773bdf226dffa5720d85a13501fba # v0.4.3 diff --git a/.github/workflows/release-github.yml b/.github/workflows/release-github.yml index dcb295a..937cfad 100644 --- a/.github/workflows/release-github.yml +++ b/.github/workflows/release-github.yml @@ -44,6 +44,8 @@ jobs: steps: - name: checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: check build artifact existence uses: softwareforgood/check-artifact-v4-existence@f988c59be23773bdf226dffa5720d85a13501fba # v0.4.3 diff --git a/.github/workflows/security-scan-artifacts.yml b/.github/workflows/security-scan-artifacts.yml index d9d4533..bca6236 100644 --- a/.github/workflows/security-scan-artifacts.yml +++ b/.github/workflows/security-scan-artifacts.yml @@ -64,6 +64,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 + persist-credentials: false # Check if build artifacts exist - name: check if build artifact exists @@ -97,7 +98,7 @@ jobs: - name: upload trivy fs SARIF if: always() && steps.trivy-fs.outcome != 'skipped' - uses: github/codeql-action/upload-sarif@v4 + uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: sarif_file: "trivy-fs-results.sarif" category: "trivy-filesystem" @@ -117,7 +118,7 @@ jobs: - name: upload grype SARIF if: always() && steps.grype.outcome != 'skipped' - uses: github/codeql-action/upload-sarif@v4 + uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: sarif_file: ${{ steps.grype.outputs.sarif }} category: "grype" @@ -198,7 +199,7 @@ jobs: - name: upload docker trivy SARIF if: always() && steps.docker-scan.outcome != 'skipped' - uses: github/codeql-action/upload-sarif@v4 + uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: sarif_file: trivy-image-*.sarif category: trivy-docker-pre-publish diff --git a/.github/workflows/security-scan-dast.yml b/.github/workflows/security-scan-dast.yml index 2b9e4af..c42c30a 100644 --- a/.github/workflows/security-scan-dast.yml +++ b/.github/workflows/security-scan-dast.yml @@ -56,6 +56,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 + persist-credentials: false - name: zap baseline scan id: zap-scan diff --git a/.github/workflows/security-scan-source.yml b/.github/workflows/security-scan-source.yml index 197806f..2cade0d 100644 --- a/.github/workflows/security-scan-source.yml +++ b/.github/workflows/security-scan-source.yml @@ -84,6 +84,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 + persist-credentials: false # Setup Python once for all tools (Semgrep, Bandit, pip-audit) - name: setup python (from pyproject.toml for uv, 3.14 otherwise) @@ -135,7 +136,7 @@ jobs: - name: upload semgrep SARIF if: always() - uses: github/codeql-action/upload-sarif@v4 + uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: sarif_file: semgrep.sarif continue-on-error: true diff --git a/.github/workflows/test-and-build.yml b/.github/workflows/test-and-build.yml index ff4d5e7..f2d159d 100644 --- a/.github/workflows/test-and-build.yml +++ b/.github/workflows/test-and-build.yml @@ -122,6 +122,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 + persist-credentials: false - name: cache dependencies uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0