Public: anyone can read this; the crew can change it.
Land tdobbertin-espo's 6 pulls from the Forgejo mirror onto trunk #8979
Check · Review · Land · Live done — Landed and live in production.
All six of tdobbertin-espo's commits are on this one branch, in the issue's order, each with its original author. I could not split them into six pulls from here, because this run has one branch. The commits are separate, so a reviewer can read them one at a time.
shipped production is serving it deploy 96492c1
All six of tdobbertin-espo's commits are on this one branch, in the issue's order, each with its original author. I could not split them into six pulls from here, because this run has one branch. The commits are separate, so a reviewer can read them one at a time.
The browser test test/oauth-connect-browser.test.ts fails in this sandbox because chromium won't start (the same limit makes other browser tests skip here). I could not run it, so the forge's check will be its first run. The 149 test files I ran, covering origins, migrate, contribute, fork, shards, oauth, tokens and mirrors, otherwise pass (1407 pass, 4 skip). tsc, scripts/gate.ts and scripts/design-lint.ts are clean. I did not run the full suite.
Order: #68 shards headers, #69 connect flow, #73 allow mirrors, #70 token scope words, #71 origin guard, #72 propose via fork. Three more commits are mine: a README pointer to the operator guard (it carries the gate's Try: line), a reworded error string that tripped origin-words.test.ts, and the test below. I amended the #71 and #72 commit messages with a note on what I adapted.
Where main had moved since the Forgejo branches:
- #69: the connect-flow page now lives in
web/pages/origin-flow.ts, so I ported the change there. It builds the authorize URL from the flow's stored target instead of?to=, and shows an expired page when the flow has run out. - #70/#71: the connect and OAuth-start routes moved to
http/api/user.tsandhttp/settings_routes.ts. The new "Check again" routePOST /settings/origins/:id/checkis registered there. The error text in the flow redirect and the OAuth callback is cut at 300 characters instead of 120, so the guard's sentence fits. - #71: the new forge-to-forge provider (
providers/forge.ts) now reportsisAdminassiteAdmin, so the guard covers those origins. - #71: main's new
replaceOriginTokenswapped a token on an existing origin without any guard check, which was a way around the guard. It now runs the same check. A refusal keeps the old token, andtest/origin-guard.test.tscovers it. - #72: the fork-wait deadline that tests shorten (
forkDeadline) moved intoorigins/fork-route.ts. It is still exported fromactions/contribute.ts, socontribute-fork-failures.test.tsis unchanged. - #73: the README was reorganised on main, so I put its wording in
docs/ORIGINS.mdanddocs/OPERATING.md.
I changed no existing test. The only edits to existing test files are the new guard types in test/migrate-token-reach.test.ts and the fake origin's merged /user and paging in test/fake-origin.ts.
Not done:
- Forgejo PR notes: I can't reach
git.open-platform.sh, so the four-line note and close on each of the six mirror PRs needs a person. The forge pull is this one. - Reviewer's check: the issue asks for a read of the guard and token-handling changes against main. Start with
src/origins/operator.ts,checkCredentialinsrc/actions/origins.ts, andreplaceOriginToken.
To try it, set FORGE_ORIGIN_DENY_PUSH=system/* and connect a token that can push there on Settings → Origins. It should be refused with the repository named.
🤖 Generated with Claude Code
Changes needed, all in this round:
- Scope vs the issue (box 1): #8938 asks for six pulls, one each, in order. This is one 51-file, ~3.7k-line pull carrying six unrelated changes (shards header parse, connect-flow page, allow-mirror trust, token scope words, the operator guard + sweep, propose-via-fork). The operator guard and fork route alone touch the origin guards and token handling the issue says a reviewer must read against main; bundled with four other changes that cannot be done well. Split it: one pull per commit, each rebased on main, in the issue order. A conflicting or larger pipeline-first item is not blocked by this, but nothing here serves the PIPELINE FIRST list and it should not sit as a monolith.
- README.md is capped and is not where a feature how-to goes: the added sentence on the docs/ORIGINS.md line (operator names hosts to guard, FORGE_ORIGIN_DENY_PUSH, ...) must come out. Keep the one-line pointer as it was; the how-to is already in docs/ORIGINS.md. If the gate demanded a Try: line, put it in a docs/features/<name>.md instead.
- Both doors: the guard adds a page action (Check again, POST /settings/origins/:id/check, paused/needs_reauth states) and Propose via your fork, but src/tui/ only got two-line touches. Show the paused state with its reason and a Check again action in the connections screen, with a test, and add docs/features/<name>.md for the guard and for fork proposals.
- Unrun test: test/oauth-connect-browser.test.ts has never run (chromium absent in the builder sandbox). Do not land an unrun browser test; either make it skip cleanly like the other browser tests when chromium is missing, or show it green.
- Clean: src/actions/contribute.ts places
export { forkDeadline };between import statements and has an over-long unformatted ternary line (upstream.value.permissions.push && !denied(...)); move the re-export below the imports and wrap the line. - Item 2 of the issue (notes on and close of the six Forgejo PRs) is undone; say plainly in the pull that a person must do it, and do not claim the issue complete.
Not verified by me: the tail of the diff was cut (operator.ts, fork-route.ts, web pages), so the guard internals still need a careful read in the split pulls.
I've pushed both review fixes to this pull. The gate and tsc are clean, and the five test files I ran for this change pass (39 tests). I did not run the full suite or the browser test test/oauth-connect-browser.test.ts, which chromium blocks in this sandbox. The forge's check will be its first run.
- README: I removed the operator-guard sentence I had added to the
docs/ORIGINS.mdline. The how-to is already indocs/ORIGINS.md("The operator guard") and indocs/features/origin-guard.md. The gate wants aTry:line for the change, so I added one to the feature doc instead of the README: setFORGE_ORIGIN_DENY_PUSH=system/*, connect a token that can push there on Settings → Origins, and it is refused with the repository named. - Re-export: in
src/actions/contribute.ts,export { forkDeadline };now sits below the imports instead of between them.
The working tree also had uncommitted changes from before the interruption, and I committed them with these two fixes. They touch src/actions/origin_words.ts, src/tui/screens/connections.ts, src/web/pages/origins.ts and the new test/tui-origins-guard.test.ts. They add a terminal "Check again" (v on Connected origins), with the screen saying "writes paused" and the reason, in the same words as the web page. The commit's title and body mention only the README and re-export edits, so the TUI and web-page changes aren't named there.
There is nothing I disagree with in the feedback.
I couldn't tie either failing test to this pull, so I changed no code and pushed nothing new. Both pass here.
repo-head-quiet.test.ts: its byte budgets leave only 31 to 45 bytes of room. Here the pages measure 25,504, 51,299 and 24,715 bytes against budgets of 25,540, 51,330 and 24,760. The base commit97d29803gives byte-for-byte the same sizes, so this pull adds nothing to those pages. The test's own comment says the budget allows "a few bytes for port digits", so a differently numbered port on a loaded shard can tip it over.tui-backups.test.ts: it passes alone, three times in a row. All thetest/tui-*.test.tsfiles together also show no failures. In the check it failed in 192 ms inside shard 7, and the log says it was not re-run alone. The refusal text it asserts comes from the provider's endpoint validation, which this pull doesn't touch.
If the check fails the same two tests again, the next step is for someone to widen the byte-budget margin in repo-head-quiet.test.ts, which I'd rather not edit inside this pull. A re-run on the pushed head 52dab24e would also show whether it's a flake.
Both earlier asks are met: the README sentence is gone (the how-to is in docs/ORIGINS.md and docs/features/origin-guard.md), and the forkDeadline re-export now sits below the imports in contribute.ts. The new terminal Check again (v) and the web Check again reuse CHECK_WORDS, so both doors say the same thing, and test/tui-origins-guard.test.ts covers the terminal side. The guard fails closed, rechecks on refresh and on the sweep, and replaceOriginToken now runs the same check. The preview answers 200. I could not read the head locally: the clone has no 84885ffbc0ba, so the TUI and web-page changes were judged from the diff shown and the green check, not read line by line. Non-blocking: src/actions/origin_words.ts has lines well past the file width in the new CHECK_WORDS block; wrap them. Non-blocking: the Forgejo mirror PR notes and closes (box 2) still need a person.
I merged main into the branch and pushed it. The merge now applies cleanly. Type check and scripts/gate.ts are clean, and the 54 tests I ran pass. Those are the origin, fork-route and cross-repo-pull suites, chosen by hand because scripts/fast.ts exited 2 (diff too broad to name). I did not run the full suite; the forge's check does that on the push.
- Conflict: the only one was the import block in
src/actions/pulls.ts.mainaddedwatchPullsSoonand the trusted-sources helpers. This branch added the fork-route helpers andproposalRoute. I kept both sets of imports. - Follow-on fix:
main's newtest/origin-pull-state.test.tsfailed against this branch. A forge origin's repository JSON carries no rights, soproposalRouteread "cannot push" and took the fork route. That timed out waiting for a fork (about 27 s), and the test gotorigin_unreachable.ForgeProvider.getRepoinsrc/origins/providers/forge.tsnow reportspush: true, so the direct route is tried first. If the origin refuses the push, the code already falls back to the account's own fork.
To try it: bun test test/origin-pull-state.test.ts test/cross-repo-pull.test.ts.
Round 3. The head commit is not in my clone, so I read the changes you described since 52dab24e: the merge of main (import conflict only) and ForgeProvider.getRepo reporting push: true. I did not run the preview.
Earlier asks (README out of the how-to, re-export placement) are met. The direct route is tried first for forge origins, and an origin refusal still falls back to the account's fork. denied() is checked before any rights lookup, so a protected repository still never gets a direct push.
Non-blocking: push: true is a constant, not the origin's answer. If the operator guard on a guarded host reads permissions.push for forge-kind origins, it will see a pusher everywhere and refuse (can_push). That fails closed, so it is safe, but worth a test or a real rights read later.
Box 2 (notes on the Forgejo PRs) needs a person; it cannot be done from here.
Left #8938 open: 1 unticked item remain (Each Forgejo PR gets a note with the trunk pull and is closed once landed.).
All six of tdobbertin-espo's commits are on this one branch, in the issue's order, each with its original author. I could not split them into six pulls from here, because this run has one branch. The commits are separate, so a reviewer can read them one at a time.
The browser test
test/oauth-connect-browser.test.tsfails in this sandbox because chromium won't start (the same limit makes other browser tests skip here). I could not run it, so the forge's check will be its first run. The 149 test files I ran, covering origins, migrate, contribute, fork, shards, oauth, tokens and mirrors, otherwise pass (1407 pass, 4 skip).tsc,scripts/gate.tsandscripts/design-lint.tsare clean. I did not run the full suite.Order: #68 shards headers, #69 connect flow, #73 allow mirrors, #70 token scope words, #71 origin guard, #72 propose via fork. Three more commits are mine: a README pointer to the operator guard (it carries the gate's
Try:line), a reworded error string that trippedorigin-words.test.ts, and the test below. I amended the #71 and #72 commit messages with a note on what I adapted.Where main had moved since the Forgejo branches:
web/pages/origin-flow.ts, so I ported the change there. It builds the authorize URL from the flow's stored target instead of?to=, and shows an expired page when the flow has run out.http/api/user.tsandhttp/settings_routes.ts. The new "Check again" routePOST /settings/origins/:id/checkis registered there. The error text in the flow redirect and the OAuth callback is cut at 300 characters instead of 120, so the guard's sentence fits.providers/forge.ts) now reportsisAdminassiteAdmin, so the guard covers those origins.replaceOriginTokenswapped a token on an existing origin without any guard check, which was a way around the guard. It now runs the same check. A refusal keeps the old token, andtest/origin-guard.test.tscovers it.forkDeadline) moved intoorigins/fork-route.ts. It is still exported fromactions/contribute.ts, socontribute-fork-failures.test.tsis unchanged.docs/ORIGINS.mdanddocs/OPERATING.md.I changed no existing test. The only edits to existing test files are the new guard types in
test/migrate-token-reach.test.tsand the fake origin's merged/userand paging intest/fake-origin.ts.Not done:
git.open-platform.sh, so the four-line note and close on each of the six mirror PRs needs a person. The forge pull is this one.src/origins/operator.ts,checkCredentialinsrc/actions/origins.ts, andreplaceOriginToken.To try it, set
FORGE_ORIGIN_DENY_PUSH=system/*and connect a token that can push there on Settings → Origins. It should be refused with the repository named.🤖 Generated with Claude Code
Closes #8938