From 07b109d2196b26ee87a14a7c01c898b370957f56 Mon Sep 17 00:00:00 2001 From: Kerem Proulx Date: Mon, 23 Mar 2026 14:31:48 -0400 Subject: [PATCH 1/3] fix: harden CI/CD workflows per zizmor audit findings Remediate all zizmor findings across both workflow files: ci.yml: - Add permissions: {} at workflow level and contents: read at job level - Add persist-credentials: false to checkout - Pin actions/checkout and actions/setup-node to SHA hashes release.yml: - Add persist-credentials: false to checkout - Pin actions/checkout and actions/setup-node to SHA hashes - Add environment: release to the job for secrets scoping - Replace ${{ steps.check.outputs.* }} in run blocks with env variables - Replace softprops/action-gh-release with gh release create --- .github/workflows/ci.yml | 13 ++++++++---- .github/workflows/release.yml | 37 ++++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9087be..bbc2ec2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,21 +9,28 @@ on: pull_request: branches: [main, master] +permissions: {} + jobs: build: name: Build & Test runs-on: ubuntu-latest + permissions: + contents: read + strategy: matrix: node-version: [18, 20, 22] steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ matrix.node-version }} @@ -35,5 +42,3 @@ jobs: - name: Verify CLI is executable run: node dist/bin/index.js --help - - diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2345cb3..5158a3d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,15 +17,17 @@ jobs: release: name: Release runs-on: ubuntu-latest + environment: release steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 + persist-credentials: false - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: "20" registry-url: "https://registry.npmjs.org" @@ -65,8 +67,10 @@ jobs: - name: Create and push git tag if: steps.check.outputs.should_publish == 'true' + env: + RELEASE_VERSION: ${{ steps.check.outputs.version }} run: | - TAG="v${{ steps.check.outputs.version }}" + TAG="v${RELEASE_VERSION}" # Check if the tag already exists on the remote if git ls-remote --tags origin "$TAG" | grep -q "$TAG"; then @@ -80,12 +84,15 @@ jobs: - name: Generate release notes if: steps.check.outputs.should_publish == 'true' + env: + RELEASE_VERSION: ${{ steps.check.outputs.version }} + RELEASE_PACKAGE: ${{ steps.check.outputs.package }} run: | # Get the previous tag PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") if [ -n "$PREV_TAG" ]; then - echo "Generating changelog from $PREV_TAG to v${{ steps.check.outputs.version }}" + echo "Generating changelog from $PREV_TAG to v${RELEASE_VERSION}" COMMITS=$(git log --pretty=format:"- %s (%h)" "$PREV_TAG"..HEAD --no-merges) else echo "No previous tag found, listing recent commits" @@ -99,18 +106,20 @@ jobs: echo "## Installation" >> release_notes.md echo "" >> release_notes.md echo '```bash' >> release_notes.md - echo "npm install ${{ steps.check.outputs.package }}@${{ steps.check.outputs.version }}" >> release_notes.md + echo "npm install ${RELEASE_PACKAGE}@${RELEASE_VERSION}" >> release_notes.md echo '```' >> release_notes.md - name: Create GitHub Release if: steps.check.outputs.should_publish == 'true' - uses: softprops/action-gh-release@v2 - with: - tag_name: v${{ steps.check.outputs.version }} - name: v${{ steps.check.outputs.version }} - body_path: release_notes.md - draft: false - prerelease: ${{ contains(steps.check.outputs.version, '-') }} - generate_release_notes: false env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_VERSION: ${{ steps.check.outputs.version }} + run: | + PRERELEASE_FLAG="" + if [[ "${RELEASE_VERSION}" == *-* ]]; then + PRERELEASE_FLAG="--prerelease" + fi + gh release create "v${RELEASE_VERSION}" \ + --title "v${RELEASE_VERSION}" \ + --notes-file release_notes.md \ + $PRERELEASE_FLAG From 895ee88da479c2ef250811177a6eaa7e9f49c9e5 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 23 Mar 2026 18:36:31 +0000 Subject: [PATCH 2/3] Fix: Remove persist-credentials: false from release workflow to allow git push The release workflow needs to push git tags, which requires authentication. Setting persist-credentials: false removes the credential helper configured by actions/checkout, causing git push to fail. Removing this setting allows the default behavior (persist-credentials: true) which preserves credentials for authenticated git operations. --- .github/workflows/release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5158a3d..07c328e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,6 @@ jobs: uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 - persist-credentials: false - name: Setup Node.js uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 From 6025e2892a29976f1c996ff869ff86a3d3992c95 Mon Sep 17 00:00:00 2001 From: Kerem Proulx Date: Mon, 23 Mar 2026 14:51:45 -0400 Subject: [PATCH 3/3] drop persist-credentials: false from release workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The artipacked finding doesn't apply here — this workflow never uploads artifacts, so there's no vector for credential leakage. Keeping credentials allows the downstream git push step to work. Added inline zizmor suppression comment. --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 07c328e..2abf77c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,6 +21,7 @@ jobs: steps: - name: Checkout code + # zizmor: ignore[artipacked] — no artifact uploads in this workflow uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0