From a08470c985460e0b78bf8133db30a0befc2fe5c4 Mon Sep 17 00:00:00 2001 From: bearomorphism <26526132+bearomorphism@users.noreply.github.com> Date: Sat, 9 May 2026 15:16:47 +0800 Subject: [PATCH 1/2] feat(examples): add PR bump preview example Adds an example workflow showing how to run `cz bump --dry-run` against incoming pull requests and post (or update) a sticky comment with the preview. Useful for catching unexpected version bumps before merging. Closes commitizen-tools/commitizen#1510 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- examples/pr-bump-preview.yaml | 88 +++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 examples/pr-bump-preview.yaml diff --git a/examples/pr-bump-preview.yaml b/examples/pr-bump-preview.yaml new file mode 100644 index 0000000..6ce6b44 --- /dev/null +++ b/examples/pr-bump-preview.yaml @@ -0,0 +1,88 @@ +# Post (or update) a sticky comment on every PR with the version bump +# that would happen if the PR were merged. Useful for catching unexpected +# version bumps before merging. +# +# Trigger: pull_request_target so the workflow has pull-requests: write +# permission for fork PRs too. Only `cz bump --dry-run` is executed +# against the checked-out PR commits — no PR-controlled scripts are run, +# so this is safe. +name: PR bump preview + +on: + pull_request_target: + types: [opened, reopened, synchronize, ready_for_review] + +permissions: + contents: read + pull-requests: write + +jobs: + bump-preview: + if: ${{ github.event.pull_request.draft == false }} + runs-on: ubuntu-latest + steps: + - name: Check out PR head + uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + fetch-tags: true + + - uses: commitizen-tools/setup-cz@main + with: + set-git-config: false + + - name: Run cz bump --dry-run + id: dry-run + run: | + set +e + output="$(cz bump --dry-run --yes 2>&1)" + status=$? + set -e + { + echo "status=${status}" + echo "output<<__CZ_BUMP_PREVIEW__" + printf '%s\n' "${output}" + echo "__CZ_BUMP_PREVIEW__" + } >> "$GITHUB_OUTPUT" + + - name: Build comment body + env: + STATUS: ${{ steps.dry-run.outputs.status }} + OUTPUT: ${{ steps.dry-run.outputs.output }} + run: | + { + # Hidden marker used by create-or-update-comment to find and + # replace the previous preview instead of stacking comments. + echo "" + echo "## 🔍 Commitizen bump preview" + echo "" + case "${STATUS}" in + 0) + echo "Merging this PR will produce the following bump:" + echo "" + echo '```' + printf '%s\n' "${OUTPUT}" + echo '```' + ;; + 21) + # NoneIncrementExit — see commitizen exit codes. + echo "No commits in this PR are eligible for a version bump." + ;; + *) + echo "⚠️ \`cz bump --dry-run\` exited with status \`${STATUS}\`:" + echo "" + echo '```' + printf '%s\n' "${OUTPUT}" + echo '```' + ;; + esac + } > comment.md + + - uses: peter-evans/create-or-update-comment@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.pull_request.number }} + body-path: comment.md + body-includes: "" + edit-mode: replace From 69f9410e6692dff3009b377055def4a4ed0c2ab5 Mon Sep 17 00:00:00 2001 From: bearomorphism <26526132+bearomorphism@users.noreply.github.com> Date: Sat, 9 May 2026 16:50:03 +0800 Subject: [PATCH 2/2] fix(examples): gate PR bump preview to same-repo PRs only Mirrors the security fix on commitizen-tools/commitizen#1957: * `cz bump` can render Jinja templates from the working directory when `update_changelog_on_bump` is set in config, using a non-sandboxed loader. Under `pull_request_target` this would let a fork PR execute arbitrary code with a write token, so gate the job to same-repo PRs only (`head.repo == base.repo`). * Add `persist-credentials: false` on `actions/checkout` as defense in depth. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- examples/pr-bump-preview.yaml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/pr-bump-preview.yaml b/examples/pr-bump-preview.yaml index 6ce6b44..69d97eb 100644 --- a/examples/pr-bump-preview.yaml +++ b/examples/pr-bump-preview.yaml @@ -3,9 +3,11 @@ # version bumps before merging. # # Trigger: pull_request_target so the workflow has pull-requests: write -# permission for fork PRs too. Only `cz bump --dry-run` is executed -# against the checked-out PR commits — no PR-controlled scripts are run, -# so this is safe. +# permission. The job is gated to same-repo PRs only — fork PRs are +# skipped because `cz bump` can render Jinja templates from the checked-out +# workspace whenever `update_changelog_on_bump` is set in config, and we +# don't want to execute fork-controlled templates with the workflow's +# elevated permissions. name: PR bump preview on: @@ -18,7 +20,12 @@ permissions: jobs: bump-preview: - if: ${{ github.event.pull_request.draft == false }} + if: > + ${{ + github.event.pull_request.draft == false && + github.event.pull_request.head.repo.full_name == + github.event.pull_request.base.repo.full_name + }} runs-on: ubuntu-latest steps: - name: Check out PR head @@ -27,6 +34,8 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 fetch-tags: true + # Defense in depth: don't write the workflow token to .git/config. + persist-credentials: false - uses: commitizen-tools/setup-cz@main with: