From 9a81e9bd8e808a078d99e3bfbfc4b95a272974de Mon Sep 17 00:00:00 2001 From: Theo Ephraim Date: Thu, 25 Jun 2026 10:39:42 -0700 Subject: [PATCH 1/4] docs: lead CI check with unprivileged pull_request, harden fork-comment workflow for checkout@v7 Invert the PR-check recommendation: the default is now a single `ci check` step in the existing pull_request workflow (forks get the check but no comment), with pull_request_target demoted to an opt-in "Commenting on fork PRs" section. Apply the actions/checkout@v7 fork-checkout change (enforced now, backported to floating tags on July 16, 2026): bump checkouts to @v7 and add allow-unsafe-pr-checkout: true on the read-only ./pr checkout in both the recommended workflow and our own dogfooding bumpy-check.yaml. Without this the fork-comment workflow would start failing once the backport lands. - docs/github-actions.md: restructure + flag fix + 3rd security rule - docs/prereleases.md: generalize the now-non-default check trigger note - .github/workflows/bumpy-check.yaml: @v7 + flag on the fork job --- .github/workflows/bumpy-check.yaml | 11 +++++--- docs/github-actions.md | 43 +++++++++++++++++------------- docs/prereleases.md | 2 +- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/.github/workflows/bumpy-check.yaml b/.github/workflows/bumpy-check.yaml index 1633ef5..c26a29d 100644 --- a/.github/workflows/bumpy-check.yaml +++ b/.github/workflows/bumpy-check.yaml @@ -28,7 +28,9 @@ jobs: if: github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + # Same-repo PR head — not a fork, so checkout@v7's fork-checkout block + # doesn't apply here and no allow-unsafe-pr-checkout flag is needed. + - uses: actions/checkout@v7 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 # history to diff bump files against the PR base branch @@ -49,16 +51,19 @@ jobs: runs-on: ubuntu-latest steps: # TRUSTED base checkout (main) — bumpy is built and run from here. - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: ref: main persist-credentials: false # UNTRUSTED PR head into ./pr — only READ via --cwd, never built or run. - - uses: actions/checkout@v6 + # checkout@v7 blocks fork-PR checkout under pull_request_target by default; + # allow-unsafe-pr-checkout opts in — safe because ./pr is never run. + - uses: actions/checkout@v7 with: ref: ${{ github.event.pull_request.head.sha }} path: pr persist-credentials: false + allow-unsafe-pr-checkout: true - uses: oven-sh/setup-bun@v2 - run: bun install - run: bun run --filter @varlock/bumpy build diff --git a/docs/github-actions.md b/docs/github-actions.md index 9733d9f..d035471 100644 --- a/docs/github-actions.md +++ b/docs/github-actions.md @@ -16,9 +16,23 @@ These commands facilitate the following: > > The version-resolution shell snippets work as-is regardless of package manager — they only depend on `jq` and `git`, both preinstalled on GitHub-hosted runners. -## PR check workflow +## PR check -Posts/updates the release-plan comment on every PR, including PRs from forks. **Copy it as-is and you're covered** — it's structured so nothing in a fork PR can influence how bumpy is fetched or run. (If you change `main` to your own base branch, that's the only edit most repos need. See the security notes below before restructuring it.) +`bumpy ci check` confirms every PR carries a bump file and posts a release-plan comment showing what will be released. The simplest setup is one step in your existing PR workflow (or a new one triggered `on: pull_request`): + +```yaml +- run: bunx @varlock/bumpy ci check + env: + GH_TOKEN: ${{ github.token }} +``` + +Give the job `permissions: pull-requests: write`. This runs in the ordinary `pull_request` context — the same trust level as the rest of your CI — so none of the privileged-workflow precautions in the next section apply: you can `bun install` and run bumpy from your devDeps like any other CLI. (If the job already ran `bun install`, `bunx` picks up your pinned version from `node_modules`; otherwise it fetches the latest.) + +**Fork PRs get the check, but not the comment.** GitHub hands `pull_request` runs from forks a **read-only token and no secrets**, so the comment can't be posted there. `ci check` still runs and fails the job (red ✗) on a missing bump file, with the explanation in the job logs — forks stay gated correctly, you just don't get the rendered comment. For most repos that's the right trade, and it keeps you off `pull_request_target` entirely. If you do want the comment on fork PRs too, set up the dedicated workflow below. + +## Commenting on fork PRs + +Posting to a PR needs a **write** token, and GitHub only grants one to a fork PR through a privileged trigger — `pull_request_target`. That trigger runs with your write token and secrets **even though the PR is code you don't control**, so the workflow must be structured so nothing in the fork PR can influence what gets fetched or run. The one below does that — copy it as-is (changing only `main` if your base branch differs), and read the security notes before restructuring it. ```yaml # .github/workflows/bumpy-check.yaml @@ -38,17 +52,21 @@ jobs: # here, so the package-manager config in effect (bunfig.toml, .npmrc) # is YOURS, not the PR's. Hardcoded "main" (the PR controls its own # base ref); change it to your base branch. - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: ref: main persist-credentials: false # 2. UNTRUSTED PR head into ./pr — only READ from here, never run it. - - uses: actions/checkout@v6 + # actions/checkout@v7 refuses to fetch fork PR code under + # pull_request_target by default; `allow-unsafe-pr-checkout` opts back + # in. It's safe HERE only because ./pr is never installed or run. + - uses: actions/checkout@v7 with: ref: ${{ github.event.pull_request.head.sha }} path: pr persist-credentials: false + allow-unsafe-pr-checkout: true - uses: oven-sh/setup-bun@v2 @@ -69,10 +87,11 @@ jobs: ### ⚠️ Security essentials -`pull_request_target` carries a **write token and secrets even on fork PRs** — that's what lets it comment on forks, and why a PR author must never be able to influence what runs. The workflow above handles this; two rules to preserve if you adapt it: +`pull_request_target` carries a **write token and secrets even on fork PRs** — that's what lets it comment on forks, and why a PR author must never be able to influence what runs. The workflow above handles this; three rules to preserve if you adapt it: - **Never execute PR code** — no `bun install` / `npm install` (postinstall scripts run), no `bun run