From 8997da53d12414033d60fab1061292d391a005b6 Mon Sep 17 00:00:00 2001 From: Yu-Ting Hsiung Date: Sun, 8 Jun 2025 18:47:57 +0800 Subject: [PATCH 1/3] feat: bump dry run github action --- .../workflows/pr-cz-dry-run-bump-comment.yml | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/pr-cz-dry-run-bump-comment.yml diff --git a/.github/workflows/pr-cz-dry-run-bump-comment.yml b/.github/workflows/pr-cz-dry-run-bump-comment.yml new file mode 100644 index 0000000..82ac300 --- /dev/null +++ b/.github/workflows/pr-cz-dry-run-bump-comment.yml @@ -0,0 +1,41 @@ +name: CZ Dry Run Bump on PR + +on: + pull_request: + types: [opened, synchronize] + +jobs: + cz_dry_run_comment: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Install dependencies + run: | + pip install poetry + poetry install + + - name: Run cz bump --dry-run + run: | + echo '## 🔍 Commitizen Dry Run Preview' > comment.md + echo '```' >> comment.md + poetry run cz bump --dry-run >> comment.md + echo '```' >> comment.md + + - name: Comment on PR + 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: "## 🔍 Commitizen Dry Run Preview" + edit-mode: replace From 55cf4e2bb4a26ce667560c23978e65f9f4f9e108 Mon Sep 17 00:00:00 2001 From: bearomorphism <26526132+bearomorphism@users.noreply.github.com> Date: Sat, 9 May 2026 15:15:16 +0800 Subject: [PATCH 2/3] feat: rework PR bump preview workflow Replace the previous draft (poetry-based) attempt with a simpler, robust implementation: * Use commitizen-tools/setup-cz instead of installing Poetry/cz from the project lockfile. The action repo doesn't need its own Python toolchain to run cz. * Trigger on pull_request_target so the workflow has pull-requests: write even for fork PRs. Only `cz bump --dry-run` is executed, so PR-controlled scripts are not run. * Capture the dry-run exit status. Treat exit code 21 (NoneIncrementExit) as 'no eligible commits' instead of a hard failure, and surface other non-zero codes in the comment. * Use a hidden HTML marker so the comment is replaced (rather than duplicated) on every push. Closes commitizen-tools/commitizen#1510 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/pr-bump-preview.yml | 82 +++++++++++++++++++ .../workflows/pr-cz-dry-run-bump-comment.yml | 41 ---------- 2 files changed, 82 insertions(+), 41 deletions(-) create mode 100644 .github/workflows/pr-bump-preview.yml delete mode 100644 .github/workflows/pr-cz-dry-run-bump-comment.yml diff --git a/.github/workflows/pr-bump-preview.yml b/.github/workflows/pr-bump-preview.yml new file mode 100644 index 0000000..8a32f6c --- /dev/null +++ b/.github/workflows/pr-bump-preview.yml @@ -0,0 +1,82 @@ +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: + # Using pull_request_target so the workflow has pull-requests: write + # access for fork PRs. The job only runs `cz bump --dry-run`, a + # read-only command, so PR-controlled scripts are not executed. + - name: Check out PR head + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + fetch-tags: true + + - name: Set up Commitizen + 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: | + { + 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) + 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 + + - name: Post or update PR comment + 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 diff --git a/.github/workflows/pr-cz-dry-run-bump-comment.yml b/.github/workflows/pr-cz-dry-run-bump-comment.yml deleted file mode 100644 index 82ac300..0000000 --- a/.github/workflows/pr-cz-dry-run-bump-comment.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: CZ Dry Run Bump on PR - -on: - pull_request: - types: [opened, synchronize] - -jobs: - cz_dry_run_comment: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.13" - - - name: Install dependencies - run: | - pip install poetry - poetry install - - - name: Run cz bump --dry-run - run: | - echo '## 🔍 Commitizen Dry Run Preview' > comment.md - echo '```' >> comment.md - poetry run cz bump --dry-run >> comment.md - echo '```' >> comment.md - - - name: Comment on PR - 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: "## 🔍 Commitizen Dry Run Preview" - edit-mode: replace From 234db2305afc664c3b8684197e72fee1ff3aef1d 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 3/3] fix(ci): 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> --- .github/workflows/pr-bump-preview.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr-bump-preview.yml b/.github/workflows/pr-bump-preview.yml index 8a32f6c..bd7f756 100644 --- a/.github/workflows/pr-bump-preview.yml +++ b/.github/workflows/pr-bump-preview.yml @@ -10,18 +10,30 @@ permissions: jobs: bump-preview: - if: ${{ github.event.pull_request.draft == false }} + # Skip drafts, and skip fork PRs entirely. `pull_request_target` runs with + # the base repo's GITHUB_TOKEN (write access to PR comments). `cz bump` + # can render Jinja templates from the checked-out workspace whenever + # `update_changelog_on_bump` is set in config, and the renderer is not + # sandboxed (FileSystemLoader('.')) — running it against fork-controlled + # files would risk RCE / token exfiltration. Same-repo PRs are written by + # collaborators who already have push access, so the same risk doesn't + # apply. + 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: - # Using pull_request_target so the workflow has pull-requests: write - # access for fork PRs. The job only runs `cz bump --dry-run`, a - # read-only command, so PR-controlled scripts are not executed. - name: Check out PR head uses: actions/checkout@v4 with: 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 - name: Set up Commitizen uses: commitizen-tools/setup-cz@main