From 67c67809d1cfe07e5098749c544dadf97f5d35e7 Mon Sep 17 00:00:00 2001 From: Tyler Dixon Date: Wed, 29 Jul 2026 16:08:24 -0700 Subject: [PATCH] ci: harden test.yaml and docs.yaml for zizmor Split out of #766 at Jeff's request, so that PR can stay focused on the release checks. This is a pre-existing, repo-wide condition rather than anything the gate introduced: the zizmor scan only runs when a workflow file changes, so it fires against whatever state the file was already in. Both workflows, since he asked for docs.yaml too: - **All 14 action references pinned to commit SHAs**, with the resolved release in a trailing comment so versions stay legible and Dependabot can still bump them. Clears `unpinned-uses`, the only mandatory audit. - **Top-level `permissions: contents: read`.** Neither workflow writes to the repo through GITHUB_TOKEN; the publish job authenticates to npm separately, now via the Google npm service. Clears `excessive-permissions`. - **`persist-credentials: false` on all four checkouts.** The token is not needed after the clone, and leaving it in .git/config exposes it to every later step. Clears `artipacked`. Result, measured with the version CI pins (1.25.2): test.yaml 8 medium, 17 high -> 0 medium, 5 high docs.yaml 2 medium, 2 high -> no findings at all CI fails on Medium or higher, so partial fixes would not have cleared it. The 5 remaining findings on test.yaml are all `cache-poisoning`, which the org scan suppresses; fixing those means restructuring how the workflow caches around the publish path and does not belong here. No functional change to any job. Verified that main's switch of the publish registry to wombat-dressing-room is preserved. --- .github/workflows/docs.yaml | 11 +++++++++-- .github/workflows/test.yaml | 35 +++++++++++++++++++++++------------ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 8c663e98..ad806bea 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -3,15 +3,22 @@ name: Check if Reference Docs need to be regenerated on: pull_request +# Least privilege. This workflow only regenerates docs and diffs them; it never +# pushes. +permissions: + contents: read + jobs: docs: runs-on: ubuntu-latest name: Build steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false - name: Setup node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '24' cache: 'npm' diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 02641d7e..d4158b35 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -13,15 +13,22 @@ on: types: - published +# Least privilege by default. No job writes to the repo through GITHUB_TOKEN; +# the publish job authenticates to npm with NODE_AUTH_TOKEN. +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest name: Build steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false - name: Setup node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '24' cache: 'npm' @@ -31,7 +38,7 @@ jobs: id: pack-dir run: ./build.sh - name: 'Upload Artifact' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: reactfire-${{ github.run_id }} path: | @@ -49,9 +56,11 @@ jobs: name: Test Node.js ${{ matrix.node }} (Ubuntu) steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false - name: Setup node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ matrix.node }} check-latest: true @@ -59,7 +68,7 @@ jobs: - name: Install deps run: npm ci - name: Setup Java - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0 with: distribution: 'temurin' java-version: '21' @@ -67,12 +76,12 @@ jobs: run: npm install working-directory: ./functions - name: Firebase emulator cache - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ~/.cache/firebase/emulators key: firebase_emulators - name: 'Download Artifacts' - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - name: Expand Artifact run: | chmod +x reactfire-${{ github.run_id }}/unpack.sh @@ -88,9 +97,11 @@ jobs: name: Type check (React ${{ matrix.react }}) steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false - name: Setup node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '24' cache: 'npm' @@ -109,12 +120,12 @@ jobs: if: ${{ github.ref == 'refs/heads/main' || github.event_name == 'release' }} steps: - name: Setup node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '24' registry-url: 'https://wombat-dressing-room.appspot.com' - name: 'Download Artifacts' - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - name: Publish run: | cd ./reactfire-${{ github.run_id }}/