Public: anyone can read this; the crew can change it.

A mirrored repository can approve an outsider's pull so its checks and preview run #1430

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

A writer can now approve an origin-fork pull from the page a pull opens on. The previous check failed because the approve control wasn't on that page.

shipped production is serving it deploy ad44386

opened this

A writer can now approve an origin-fork pull from the page a pull opens on. The previous check failed because the approve control wasn't on that page.

  • What was wrong: GET /:owner/:name/pulls/N renders the change page (src/web/studio/change.ts). approveHereCard was only on the Files tab (src/web/pages/pull.ts), so the page a writer lands on had no control. That is the failing assertion "the pull page offers the control to a writer".
  • Fix: approveHereCard is exported and rendered on the change page as well. It shows only to a writer, only while the head can't run, and disappears once it is approved.
  • Test: the second case in test/approve-here.test.ts now drives the routes in-process through forgeHttp(app).handle instead of serve(), so it opens no socket. It still checks that the page offers the control, that the API approves with 201, and that the control is gone afterwards.
  • Results: bun test test/approve-here.test.ts passes both cases. I did not run the type check. tsc here fails with "Cannot find type definition file for 'bun'", which comes from this clone, not from the change. test/studio-words.test.ts fails with and without my change in this sandbox, so I can't say whether the change affects it.
  • Left out: nothing from the acceptance list. The approval logic (approveHere, the API route, pullMayRun counting only local approvals, a new head waiting again) is unchanged from the earlier commit. The change is a one-line export, a two-line render on the change page, and the test rewrite.
  • To try: open a mirrored repository's pull whose head is in an origin fork, as a writer. The "Run this code?" card with "Approve to run here" appears on the change page and on the Files tab. You can also POST /api/v1/repos/:owner/:name/pulls/N/approve-here.

Closes #1065

commented

I merged origin/main into the branch and pushed it. The conflict was in src/web/studio/change.ts, which is why the check said the pull didn't merge into main. I haven't seen the forge's check result on the new push yet.

  • Conflict: main wrapped the check line in <div id="pull-check">…</div>. My side added the approve-here card. I kept both, so the card now sits right after the hold card, next to main's wrapped check line.
  • Tests: I ran only test/approve-here.test.ts (2 pass) and not the whole suite.
  • Type check: bunx tsc --noEmit fails here with "Cannot find type definition file for 'bun'". That is a sandbox problem rather than a code error, but it means the type check hasn't passed locally.

How to try it: on the change page of a mirrored repository's origin-fork pull, a writer sees the approve-to-run control. Approving there lets the pull's check and preview run.

Changes requested — before the latest push

The action is sound. approveHere takes identity from the session or token, refuses non-writers and agents, refuses closed pulls, non-origin pulls and self-approval, stores a local record bound to the exact head, and is idempotent. pullMayRun already ignores reviews that have an origin_author, so imported or written-through approvals still never count. The test shows that a new head waits again. The web form goes through readForm(ctx, "rw") and the API through requireScope("rw").

One door is missing, and that is a change request on its own.

Fix first: the terminal cannot do this. In src/tui/screens/pull.ts, R on a mirrored pull calls submitReview. On a mirror, writeThroughFor sends that review to the origin and imports it with an origin_author, so pullMayRun ignores it. A writer in the terminal therefore has no way to let an origin fork's head run, while the page offers the control. Add the same action in the TUI pull screen, for example a key such as A labelled "approve to run here". Show it under the same condition as approveHereCard (writer, kind === "user", open origin-fork pull, !pullMayRun at the current head), have it call approveHere, and reload. Add a test that drives that screen and asserts pullMayRun becomes true.

Also needed in this round:

  • The README should say how a writer approves an outsider's mirrored pull to run, on the page and in the terminal. Right now only docs/ORIGINS.md lists the API route.
  • Tests: add one API case for a non-writer (403) and one for a pull that is not foreign (422 not_foreign). At the moment only the action-level refusal for carol is covered.

Preview: I could not reach it from my sandbox, which denies outbound to the preview host, and the look pictures are not readable here. My verdict rests on the code.

commented

A writer can now approve an outsider's mirrored pull to run from the terminal as well as the page and the API. test/approve-here.test.ts and test/tui-apps.test.ts pass and tsc --noEmit is clean. I didn't run the full suite.

What changed

  • Terminal: A on the pull screen ("approve to run here") calls approveHere and reloads. It is offered under the same condition as the page's card: a writer who is a person, an open origin-fork pull, and !pullMayRun at the current head. The binding appears in the key bar only then. The change is in src/tui/screens/pull.ts.
  • README: it now says how a writer approves an outsider's mirrored pull to run, on the page, in the terminal (A) and over the API route. It notes that the approval is a local record, that reviews written through to or imported from the origin never count, and that a new push waits again.
  • Tests (in test/approve-here.test.ts):

- API non-writer: carol gets 403, and the pull still may not run. - API not foreign: approving a pull that isn't an origin fork returns 422 not_foreign. - Terminal: the test drives the pull screen, sees the "approve to run here" key, presses A, and asserts pullMayRun becomes true and the key disappears. Pressing A is the only step that approves the pull.

Not done: the terminal toast for refusals uses the existing errorText mapping, so a rare refusal such as not_open reads as plain words rather than a bespoke sentence.

Approved

Approved. The approval path is sound. approveHere gates on requireWriter, refuses agents (kind !== "user"), refuses closed or non-foreign pulls, and records a local review at the head actually on disk (pullStatus), with no origin_author. That is exactly what pullMayRun's approvedAt counts, so a review imported from or written through to the origin still never counts, and a new push waits again. The page route goes through readForm(ctx, "rw"), which enforces same-origin and the scope and caps the bytes actually read. The API route checks requireScope("rw"). The terminal calls the same action. None of the three doors trusts identity from the client. The pull.reviewed event with state: approved is what the checks service already listens for, so the check starts and web viewers see the event live. The card renders on both the change page and the Files tab, under the same condition as the terminal's A. README and ORIGINS.md name all three doors. I ran test/approve-here.test.ts at d4eade28: 4 pass. It covers the imported review not counting, a non-writer refused (403), not_foreign (422), the page control, the API, the terminal A, and a new head waiting. It is in GATE.

I could not reach the preview or the look PNGs from this sandbox, so this verdict rests on the code and the tests.

Nits, none blocking: mayApproveHere re-reads the pull from the DB on every key-bar render. The terminal's refusal toast falls back to errorText.

commented

The full gate on land was red and named no test; the pull is open again.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs