From bc8826aa6dbf4f035c67128933af44afcc90fc28 Mon Sep 17 00:00:00 2001 From: Chris Burns <29541485+ChrisJBurns@users.noreply.github.com> Date: Mon, 10 Aug 2026 23:33:45 +0100 Subject: [PATCH 1/2] Clear the remaining findings in create-release-tag Every expression in this workflow's run blocks is now bound through env:. The version is the same value throughout and is checked against a semver pattern before any of these steps run, so this is consistency rather than a fix. The checkout stops persisting credentials. The single push in this job supplies its token in the remote URL, so the credential actions/checkout leaves in .git/config was never what authenticated it. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/create-release-tag.yml | 40 ++++++++++++++++-------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/.github/workflows/create-release-tag.yml b/.github/workflows/create-release-tag.yml index 0ed186b83c..19cc0bf541 100644 --- a/.github/workflows/create-release-tag.yml +++ b/.github/workflows/create-release-tag.yml @@ -35,6 +35,9 @@ jobs: uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: fetch-depth: 0 + # The one push in this job supplies its token in the remote URL, so + # the credential actions/checkout persists is never used. + persist-credentials: false - name: Read version id: version @@ -49,8 +52,9 @@ jobs: - name: Verify release PR id: verify + env: + VERSION: ${{ steps.version.outputs.version }} run: | - VERSION="${{ steps.version.outputs.version }}" # Get commit details COMMIT_MSG=$(git log -1 --pretty=%s) @@ -124,8 +128,10 @@ jobs: - name: Check if tag exists id: check-tag + env: + VERSION: ${{ steps.version.outputs.version }} run: | - TAG="v${{ steps.version.outputs.version }}" + TAG="v${VERSION}" if git rev-parse "$TAG" >/dev/null 2>&1; then echo "Tag $TAG already exists" echo "exists=true" >> $GITHUB_OUTPUT @@ -136,21 +142,28 @@ jobs: - name: Create tag if: steps.check-tag.outputs.exists == 'false' + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + VERSION: ${{ steps.version.outputs.version }} + REPOSITORY: ${{ github.repository }} run: | - TAG="v${{ steps.version.outputs.version }}" + TAG="v${VERSION}" git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git tag -a "$TAG" -m "Release $TAG" - git push https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git "$TAG" + # The token is supplied in the URL, so this push does not use the + # credential actions/checkout would otherwise leave in .git/config. + git push "https://x-access-token:${GH_TOKEN}@github.com/${REPOSITORY}.git" "$TAG" echo "Created and pushed tag: $TAG" - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - name: Check if GitHub Release exists id: check-release + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + VERSION: ${{ steps.version.outputs.version }} run: | - TAG="v${{ steps.version.outputs.version }}" + TAG="v${VERSION}" if gh release view "$TAG" >/dev/null 2>&1; then echo "GitHub Release $TAG already exists" echo "exists=true" >> $GITHUB_OUTPUT @@ -158,13 +171,11 @@ jobs: echo "GitHub Release $TAG does not exist" echo "exists=false" >> $GITHUB_OUTPUT fi - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - name: Create GitHub Release if: steps.check-release.outputs.exists == 'false' run: | - TAG="v${{ steps.version.outputs.version }}" + TAG="v${VERSION}" # Create GitHub Release (triggers releaser.yml via release event) # Note: Uses a GitHub App installation token rather than GITHUB_TOKEN, @@ -183,16 +194,19 @@ jobs: echo "Created GitHub Release: $TAG" env: GH_TOKEN: ${{ steps.app-token.outputs.token }} + VERSION: ${{ steps.version.outputs.version }} # Read out of a git commit trailer, so unlike the version — which is # checked against a semver pattern before use — this one is not # constrained by anything. Bound rather than interpolated. TRIGGERED_BY: ${{ steps.actor.outputs.triggered_by }} - name: Summary + env: + VERSION: ${{ steps.version.outputs.version }} + TAG_EXISTED: ${{ steps.check-tag.outputs.exists }} + RELEASE_EXISTED: ${{ steps.check-release.outputs.exists }} run: | - TAG="v${{ steps.version.outputs.version }}" - TAG_EXISTED="${{ steps.check-tag.outputs.exists }}" - RELEASE_EXISTED="${{ steps.check-release.outputs.exists }}" + TAG="v${VERSION}" echo "## Release Summary for \`$TAG\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY From f806ff410eceafe5ce878a9f024a2712e5031fcc Mon Sep 17 00:00:00 2001 From: Chris Burns <29541485+ChrisJBurns@users.noreply.github.com> Date: Mon, 10 Aug 2026 23:36:03 +0100 Subject: [PATCH 2/2] Stop persisting credentials in the last release checkouts Neither releaser.yml nor create-release-pr.yml contains a git push, commit or tag. GoReleaser uploads release assets through the API with the token it is given, and pushes the Homebrew formula with a separate app token; releaseo is handed the release app token explicitly. In both workflows the credential actions/checkout leaves behind is unused. Two of the three releaser jobs declare contents: read and so could not push regardless. This clears the last findings: zizmor now reports none across .github. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/create-release-pr.yml | 4 ++++ .github/workflows/releaser.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml index 9527b78a2b..df25ddc6ca 100644 --- a/.github/workflows/create-release-pr.yml +++ b/.github/workflows/create-release-pr.yml @@ -44,6 +44,10 @@ jobs: - name: Checkout uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + with: + # releaseo pushes the release branch with the app token it is given + # explicitly, not with the credential actions/checkout persists. + persist-credentials: false - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 with: diff --git a/.github/workflows/releaser.yml b/.github/workflows/releaser.yml index 7f12ea25e3..3fde5545a0 100644 --- a/.github/workflows/releaser.yml +++ b/.github/workflows/releaser.yml @@ -41,6 +41,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + with: + persist-credentials: false - name: Verify tag matches VERSION file run: | @@ -84,6 +86,7 @@ jobs: uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: fetch-depth: 0 + persist-credentials: false - id: ldflags run: | echo "commit=$GITHUB_SHA" >> $GITHUB_OUTPUT @@ -105,6 +108,7 @@ jobs: uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: fetch-depth: 0 + persist-credentials: false - name: Setup Go uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6