Skip to content

feat: fork-PR comments via pull_request + workflow_run split (+ checkout@v7 docs hardening)#142

Merged
theoephraim merged 4 commits into
mainfrom
claude/adoring-buck-35a83a
Jun 26, 2026
Merged

feat: fork-PR comments via pull_request + workflow_run split (+ checkout@v7 docs hardening)#142
theoephraim merged 4 commits into
mainfrom
claude/adoring-buck-35a83a

Conversation

@theoephraim

@theoephraim theoephraim commented Jun 25, 2026

Copy link
Copy Markdown
Member

What

Reworks how bumpy gets a release-plan comment onto fork PRs. Two parts:

  1. Docs hardening (original scope): lead with the unprivileged pull_request check as the default; apply the July-16 actions/checkout@v7 change (allow-unsafe-pr-checkout on the read-only ./pr checkout).
  2. New safer fork-comment architecture: a pull_request + workflow_run split where the privileged half never touches fork code or files — added after we audited the residual risks of the single-file pull_request_target approach.

Why the split

A fork's pull_request token is read-only at issuance (enforced server-side — REST/GraphQL/gh/curl all 403, no secrets), so the comment must be posted from a privileged base-repo run. The workflow_run split is the only design where the privileged job has no untrusted checkout, no package manager run against fork config, and reads no fork file — it just posts pre-rendered text. That removes the allow-unsafe-pr-checkout fragility, the symlink read-surface, the registry-redirect surface, and the CodeQL dismissal that the pull_request_target workflow carries.

CLI changes (@varlock/bumpy, minor)

  • ci check --emit-comment <dir> — renders the comment to <dir>/comment.md (seeds an empty file so the artifact is always present) instead of only posting it. Still posts directly when it has a write token (same-repo PRs).
  • ci comment --body-file <path> — posts a pre-rendered body. Security-critical: it resolves the target PR from the trusted workflow_run event (head_sha → PR lookup), never from the artifact (which is fork-influenced), and treats the body as data. Sets GH_REPO from GITHUB_REPOSITORY so it runs without a checkout. No-ops on a missing/empty body.

User-facing setup

The fork-comment setup is optional — only needed to show the comment on PRs from forks (the check itself already runs red/green on forks). Add --emit-comment + upload-artifact to your existing pull_request CI, and drop in a small workflow_run poster. Docs: Commenting on fork PRs. The pull_request_target approach has been removed from the docs — the split is the only documented fork-comment path.

Dogfood

Replaced our pull_request_target bumpy-check.yaml (two jobs) with a single pull_request check that emits + uploads, plus a new bumpy-comment.yaml (workflow_run) that builds main's bumpy and posts.

Tests / verification

  • New test/core/ci-comment.test.ts: resolveTargetPrNumber derives the PR from the event head_sha (and ignores a hostile #999 in the body); ci comment no-ops on missing/empty body. Full suite: 389 pass, typecheck + lint + fmt clean.
  • Smoke-tested --emit-comment (writes a real rendered comment.md) and ci comment (no-op + error paths) end-to-end.

⚠️ One-time bootstrapping note

On this PR, the new dogfood bumpy-comment.yaml (which builds main's bumpy) will fail, because ci comment doesn't exist on main until this merges. That's cosmetic — it's the poster workflow, not the PR check, and this PR's own comment still posts directly from bumpy-check.yaml (same-repo write token). It goes green automatically once merged.

…nt 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
@theoephraim theoephraim force-pushed the claude/adoring-buck-35a83a branch from 99b86bd to 9a81e9b Compare June 25, 2026 18:12
Add a safer way to comment on fork PRs than the privileged
pull_request_target workflow: run `ci check` in the normal (unprivileged)
pull_request workflow, and post the comment from a separate workflow_run
job whose privileged half never touches fork code or files.

CLI:
- `ci check --emit-comment <dir>` renders the comment to <dir>/comment.md
  (seeds an empty file so the artifact is always present) instead of only
  posting it.
- new `ci comment --body-file <path>` posts a pre-rendered body. It resolves
  the target PR from the TRUSTED workflow_run event (head_sha → PR lookup),
  never from the (fork-influenced) artifact, and treats the body as data.
  Sets GH_REPO from GITHUB_REPOSITORY so it runs without a checkout.

Docs: make the pull_request + workflow_run split the recommended fork-comment
setup; demote the single-file pull_request_target workflow to an alternative.

Dogfood: replace the pull_request_target bumpy-check.yaml (two jobs) with a
single pull_request check that emits + uploads the artifact, plus a new
bumpy-comment.yaml (workflow_run) that builds main's bumpy and posts.

Tests: resolveTargetPrNumber derives the PR from the event head_sha (and
ignores a hostile PR ref in the body); ci comment no-ops on a missing/empty
body. Adds a minor bump for @varlock/bumpy.
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

bumpy-frog

The changes in this PR will be included in the next version bump.

minor Minor releases

  • @varlock/bumpy 1.17.0 → 1.18.0

Bump files in this PR

Click here if you want to add another bump file to this PR


This comment is maintained by bumpy.

@theoephraim theoephraim changed the title docs: lead CI check with unprivileged pull_request; harden fork-comment workflow for checkout@v7 feat: fork-PR comments via pull_request + workflow_run split (+ checkout@v7 docs hardening) Jun 25, 2026
…split

- cli.md: document ci check --emit-comment and add a ci comment section
- github-actions.md: note the workflow_run default-branch gotcha, and
  tighten the untrusted-artifact wording (rendered from PR bump files /
  may execute fork code) and a stale 'next section' pointer
…p optional

- github-actions.md: remove the entire 'Alternative: pull_request_target'
  subsection (workflow + security essentials + registry-redirect details +
  CodeQL notes). The pull_request + workflow_run split is now the only
  documented way to comment on fork PRs.
- Lead the fork-comment section with a bold 'this is optional — only for fork
  PR comments' callout; drop the now-stale 'precautions below' phrasing from
  the PR check section.
- cwd.ts: the legacy pull_request_target guardrail now steers users to the
  pull_request + workflow_run setup first, with --cwd kept as a stay-on-it
  escape hatch.
@theoephraim theoephraim merged commit dc87355 into main Jun 26, 2026
6 checks passed
theoephraim added a commit that referenced this pull request Jun 26, 2026
…ollision

The #142 squash-merge dropped this rename. On main, the "Bumpy Check"
workflow's job is named `check`, which collides with the `check` job in
ci.yaml — two workflows emit the same `check` status context, making the
required-check match ambiguous.

Rename it to `bumpy-check` so the bump-file check has its own distinct status
context. The branch-protection ruleset should require `check` (CI tests) +
`bumpy-check`, replacing the now-defunct `check-local` (the old
pull_request_target job, removed in #142).
theoephraim added a commit that referenced this pull request Jun 26, 2026
…on) (#144)

## What

Re-applies the one commit the
[#142](#142) squash-merge dropped:
renaming the **Bumpy Check** workflow's job from `check` to
`bumpy-check`.

## Why

On `main` right now, two PR workflows both emit a status context named
`check`:

- `CI / check` (the test suite, in `ci.yaml`)
- `Bumpy Check / check` (the bump-file check, in `bumpy-check.yaml`)

A required status check named `check` is therefore ambiguous. Renaming
the bump-file job to `bumpy-check` gives it a distinct context.

## ⚠️ Needs a branch-protection (ruleset) change too

The "Protect main" ruleset currently requires **`check`** and
**`check-local`**. Since #142 merged, `check-local` no longer exists (it
was the old `pull_request_target` job) → it's now a **phantom required
check that blocks every PR**, including this one.

Required checks should become **`check`** (CI tests) + **`bumpy-check`**
(this PR's renamed job). The `comment` job in `bumpy-comment.yaml` (the
`workflow_run` poster) should **not** be required.

This PR stays blocked until the ruleset drops `check-local`, so the
ruleset edit and this merge go together.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant