lichen.page.review from the reviewed point 0b92cb61 to stack eb5a1653, as one PR per subsystem (review set)

full 05: The hub: one receive for the site and for clients #68

targeting full/04-site-area
Open opened by and assigned to notplants-bot.bsky.social
targeting full/04-site-area

Every push into a site's history now goes through one receive on the site's hub, whoever pushes: the site itself after each commit lichen makes, or a client over smart HTTP. Clients' git is served from the hub in every mode, and the old path, where the front server forwarded a client to git http-backend as a CGI, is deleted. The receive's rules are lichen's own code, and the only difference between pushers is how they were admitted. Since FULL-SITE-PROCESS the hub's code lives in lichen-site and runs on the site process's admin thread: the front server admits a client's git and forwards it, and relays the site's own push back to that thread.


AST-verified changes

  • SECURITY-FOLDER-AND-PRINCIPALS unit 2 (b603dbbe): site_area/hub.rs and site_area/hub/full_push.rs → admin_area/hub.rs and admin_area/hub/full_push.rs, part of site_area/ → admin_area/ (13 files renamed, crate::site_area → crate::admin_area in all lichen-server Rust). Checked by the builder: "AST equal three ways (8da73502 → b603dbbe, → bdaa795b, → 067dbe37), plants caught"; adversary rerun notify-020eb199: "all equal=True (2471/2471, renamed 13, carried 426, visibility 0, errors 0)". The non-move edits (d85a66d2: include_str! paths, literals) and the rustfmt (bdaa795b) are separate commits.

  • FULL-SITE-PROCESS 5b (#1649 on lichen.page.review, 26779036 → 0e8871fe, map machine-docs/reports/fsp-5b/move-map.json): admin_area/hub.rs, admin_area/hub/full_push.rs, git/hub_http.rs and git/hub_files.rs renamed whole from lichen-server into lichen-site, four of 34 files (19 modules and their 15 #[path] test files) moved, each re-exported where it was; the others are in #20, #23 and #25. Run notify-981f7470: "equal=True; items 5557/5557, stayed 4752, carried 805 in the 34 renamed files; visibility_changes 99, every one listed; comments compared 4991; module declarations checked 352"; plants item_edited and visibility_unlisted caught, a dropped declaration gate not caught (covered by the PR's gate table); adversary reruns equal (notify-c53fbd02). The rustfmt (eedd7e97, ad03def8) and the pub widenings for what the front calls (6a2b574d, c04bebac, 0e8871fe, each in the map) are separate commits. None of this PR's 5,510 changed lines can be skipped for these moves: every moved file was created after 09-23, so in this diff it reads as new code.


What changed and why (SITE-FRONT-BOUNDARY, "The hub", decisions 3, 7, 13, 16):

  • One receive (lichen-site/src/admin_area/hub.rs). receive runs git receive-pack confined to the hub, with lichen's config on its command line and none of the hub's own hooks. The pre-receive is lichen's own check_main, run as lichen hub-check from a hooks folder in the site's area. Before any ref moves it allows only the refs the pusher's policy names (main, and refs/dist/latest for the site), no deletions, main only forward unless the policy allows a force push (a full token, decision 7; never the site), and no symlink that leaves the tree. One refusal refuses the whole push. The pack is bounded by the owner's remaining storage (receive.maxInputSize); with none left the push is refused before git runs.
  • The site pushes (lichen-site/src/git/hub.rs, unit 4b). Each commit lichen makes is pushed right after (commit-to-hub). The site reads the hub by path, read-only; if the hub's main moved, it merges first (never a rebase), and a refusal because the hub moved merges and retries, three attempts in all. The push is built by the site itself as one smart-HTTP request on the site process's request channel, which the front server relays to the same process's admin thread (FULL-SITE-PROCESS 6c), so no child of the site reaches the hub. For a rewrite, the site holds (commits, pushes, keeps its transaction) and then resets to the hub's new main, or lets go after a timeout.
  • Clients' git goes to the hub (git/hub_http.rs, unit 5): info/refs, git-upload-pack and git-receive-pack under /git/{domain}/, the same routes in every mode, in their permission groups. The front server admits them and, since FULL-SITE-PROCESS 6c, forwards them to the site process, whose admin thread serves them from the hub (site_process/hub.rs). After a push moves main, the admin thread asks the site's main runtime to merge it (flow B) and the answer waits for that, bounded.
  • A full token's force push (hub/full_push.rs, unit 8b) is received into refs/lichen/incoming first; the rewrite sequence then moves main on the admin thread, and the client gets lichen's own report.
  • Reading a site's content safely (git/hub_files.rs): one blob of a hub commit through git, bounded, never a tree, a link or a submodule, never a checkout. The admin thread's publish (manifest, covers) and an imported site's settings use it.
  • Deleted: lichen-server/src/git/smart_http.rs (−770), which proxied clients to git http-backend.

Files

  • crates/lichen-site/src/admin_area/hub.rs (moved from lichen-server in 5b) — receive, check_main, Pusher, Policy, upload. Read this first.
  • crates/lichen-site/src/admin_area/hub/full_push.rs (moved) — the full token's push via refs/lichen/incoming.
  • crates/lichen-site/src/git/hub_http.rs (moved) — clients' smart-HTTP routes on the hub, and the merge request after a push.
  • crates/lichen-site/src/git/hub_files.rs (moved) — one bounded blob of a hub commit.
  • crates/lichen-site/src/site_process/hub.rs (874 lines, new) — the site process's hub: its admin thread serves the hub's routes with the handlers the front server served, given its one site (OwnSite), its owner's storage (OwnBudget), its main runtime through a queue (OwnRuntime, flow B), and what it tells the front (TellTheFront, flow C).
  • crates/lichen-site/src/git/hub.rs (1,818 lines) — the site's side: read, merge, build and send the push (HubTransport: the site process's request channel, or the front server's own receive in local mode), retry, hold, reset, release, merge_from_hub.
  • crates/lichen-server/src/git/smart_http.rs — deleted.

Lives elsewhere

  • The hub repository itself (create, migrate, the rewrite helpers, restore): #20.
  • /hub/git-receive-pack, which the front server relays back to the site process's admin thread: #19.
  • The rewrite sequence that moves main (lichen-site/src/git/rewrite.rs): #23. The admin thread and its router: #38. The iroh endpoint's asks of the hub (site_process/iroh_hub.rs): #28.
  • The hub-check dispatch in lichen-cli/src/main.rs: #32.
  • Tests (admin_area__hub*.rs, e2e git tests) are in the base commit.

Category: The hub: one receive for the site and for clients Size: 7 files, +4,740/−770 Rounds: round 0 at stack ae42e3c0; round 1 at 6b650b2a (SECURITY-FOLDER-AND-PRINCIPALS): hub.rs and hub/full_push.rs renamed into admin_area/ (unit 2), and path rewrites in git/hub_http.rs. Read this round in its interdiff: https://tangled.org/notplants-bot.bsky.social/lichen.page.october/pulls/21/round/1/interdiff. Round 2 at b66397c0 (FULL-SITE-PROCESS): the four hub modules moved into lichen-site (5b, AST-checked), and the new site_process/hub.rs, from which the site process's admin thread serves the hub's routes (6c); the site's push is relayed to that admin thread; the main runtime merges from the hub when the admin thread asks (flow B). Read this round in its interdiff: https://tangled.org/notplants-bot.bsky.social/lichen.page.october/pulls/21/round/2/interdiff Plans and ledger: SITE-FRONT-BOUNDARY-2026-10-17.md ("The hub", decisions 3, 7, 13, 16; units 4, 4b, 5, 8b, 9b, 10a), SITE-FRONT-BOUNDARY-U1-DESIGN-2026-10-19.md, SITE-FRONT-BOUNDARY-U8-DESIGN-2026-10-22.md §11, FULL-SITE-PROCESS-2026-10-25.md (part 6, units 5b, 6c); builder ledger SFB unit 4 rows (lines 2892–2917). Inline #[cfg(test)] modules: none. 1 file points to a test file with #[path] (the moved modules' tests came back to lichen-server in 5b's tests PR, through test-support accessors). Bucket moves: none from round 1. (Round 1 gathered these from the starting map's Git and Site area buckets.) In round 4 the four moved files stay here with their subject though they changed crates, and the new site_process/hub.rs is placed here by an explicit rule. Round 1: #5 (The hub) covered these files from 0b92cb61.

This pull request has no versions submitted yet.