From eb9745b020c5f5213ff62f70a4920c22c55be06d Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Wed, 20 May 2026 09:44:48 +0200 Subject: [PATCH 1/2] ci: add zizmor for GitHub Actions security analysis Run zizmor on every push to main and on PRs. Address all findings: - Add persist-credentials: false to all actions/checkout invocations - Add top-level permissions: contents: read to publish-pypi.yml - Convert github.event.release.* template expansions in comment-on-release.yml to env-var indirection in github-script to avoid code injection - Suppress the secrets-outside-env warning on the Claude Code action with an inline zizmor: ignore; moving to a dedicated GitHub environment is a separate infrastructure change --- .github/workflows/claude.yml | 3 ++- .github/workflows/comment-on-release.yml | 22 ++++++++++++----- .github/workflows/conformance.yml | 4 ++++ .github/workflows/deploy-docs.yml | 2 ++ .github/workflows/publish-pypi.yml | 5 ++++ .github/workflows/shared.yml | 6 +++++ .github/workflows/weekly-lockfile-update.yml | 2 ++ .github/workflows/zizmor.yml | 25 ++++++++++++++++++++ 8 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/zizmor.yml diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 59dac99dcb..18f5377cb6 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -30,12 +30,13 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 + persist-credentials: false - name: Run Claude Code id: claude uses: anthropics/claude-code-action@2f8ba26a219c06cfb0f468eef8d97055fa814f97 # v1.0.53 with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} # zizmor: ignore[secrets-outside-env] use_commit_signing: true additional_permissions: | actions: read diff --git a/.github/workflows/comment-on-release.yml b/.github/workflows/comment-on-release.yml index 15d6a1d26a..66f1fcc32a 100644 --- a/.github/workflows/comment-on-release.yml +++ b/.github/workflows/comment-on-release.yml @@ -16,13 +16,16 @@ jobs: uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 + persist-credentials: false - name: Get previous release id: previous_release uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + env: + CURRENT_TAG: ${{ github.event.release.tag_name }} with: script: | - const currentTag = '${{ github.event.release.tag_name }}'; + const currentTag = process.env.CURRENT_TAG; // Get all releases const { data: releases } = await github.rest.repos.listReleases({ @@ -54,10 +57,13 @@ jobs: - name: Get merged PRs between releases id: get_prs uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + env: + CURRENT_TAG: ${{ github.event.release.tag_name }} + PREVIOUS_TAG_JSON: ${{ steps.previous_release.outputs.result }} with: script: | - const currentTag = '${{ github.event.release.tag_name }}'; - const previousTag = ${{ steps.previous_release.outputs.result }}; + const currentTag = process.env.CURRENT_TAG; + const previousTag = JSON.parse(process.env.PREVIOUS_TAG_JSON); if (!previousTag) { console.log('No previous release found, skipping'); @@ -104,11 +110,15 @@ jobs: - name: Comment on PRs uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + env: + PR_NUMBERS_JSON: ${{ steps.get_prs.outputs.result }} + RELEASE_TAG: ${{ github.event.release.tag_name }} + RELEASE_URL: ${{ github.event.release.html_url }} with: script: | - const prNumbers = ${{ steps.get_prs.outputs.result }}; - const releaseTag = '${{ github.event.release.tag_name }}'; - const releaseUrl = '${{ github.event.release.html_url }}'; + const prNumbers = JSON.parse(process.env.PR_NUMBERS_JSON); + const releaseTag = process.env.RELEASE_TAG; + const releaseUrl = process.env.RELEASE_URL; const comment = `This pull request is included in [${releaseTag}](${releaseUrl})`; diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index d876da00b0..9c33d2936b 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -19,6 +19,8 @@ jobs: continue-on-error: true steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 with: enable-cache: true @@ -34,6 +36,8 @@ jobs: continue-on-error: true steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 with: enable-cache: true diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index d9362afd57..fcf7a6c1a7 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -34,6 +34,8 @@ jobs: steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 7ba11e86fa..573f5dafc3 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -4,6 +4,9 @@ on: release: types: [published] +permissions: + contents: read + jobs: release-build: name: Build distribution @@ -11,6 +14,8 @@ jobs: needs: [checks] steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 diff --git a/.github/workflows/shared.yml b/.github/workflows/shared.yml index efb45c8898..5f115aef89 100644 --- a/.github/workflows/shared.yml +++ b/.github/workflows/shared.yml @@ -14,6 +14,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 with: @@ -57,6 +59,8 @@ jobs: steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 @@ -83,6 +87,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 with: diff --git a/.github/workflows/weekly-lockfile-update.yml b/.github/workflows/weekly-lockfile-update.yml index 5d79d06d52..c30c72991a 100644 --- a/.github/workflows/weekly-lockfile-update.yml +++ b/.github/workflows/weekly-lockfile-update.yml @@ -15,6 +15,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 with: diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000000..2d640e6f7c --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,25 @@ +name: GitHub Actions Security Analysis + +on: + push: + branches: ["main"] + pull_request: + branches: ["**"] + +permissions: {} + +jobs: + zizmor: + runs-on: ubuntu-latest + + permissions: + security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files. + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Run zizmor 🌈 + uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 From 9c596da479234cf2b0d81526807418267720a09e Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Wed, 20 May 2026 15:43:06 +0200 Subject: [PATCH 2/2] ci: bump zizmor-action to v0.5.6 and disable uv cache in release build The newer zizmor (1.25.x, shipped by zizmor-action v0.5.6) adds a cache-poisoning audit that flags astral-sh/setup-uv with enable-cache: true in a release: published-triggered job. Disable the cache for the release-build job - release builds are infrequent and a cold cache is fine - so the new security workflow lands clean. --- .github/workflows/publish-pypi.yml | 2 +- .github/workflows/zizmor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 573f5dafc3..c72061d12b 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -20,7 +20,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1 with: - enable-cache: true + enable-cache: false version: 0.9.5 - name: Set up Python 3.12 diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 2d640e6f7c..83d3eb3817 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -22,4 +22,4 @@ jobs: persist-credentials: false - name: Run zizmor 🌈 - uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 + uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6