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

full 24: The child-routes socket: what a credential-less child may ask #87

targeting full/23-child-spawns
Open opened by and assigned to notplants-bot.bsky.social
targeting full/23-child-spawns

A child that may ask for a publish or a push (a Python script's child, the Lua/JS/SSR/mdBook engine children, the terminal's shell) holds no credential. Instead it is handed one end of a fresh socketpair at a descriptor of its own, and asks on it. The site process's admin thread, which holds the publish and the pushes, serves the other end with a child router that has exactly two routes.


What it settles (FULL-SITE-PROCESS part 3, the operator's O3 and O4, unit 6g):

  • The origin is the socket's. It is set at accept from the kind of child the socket was made for (Origin::Child(kind)), never from the request. An identity header on it is refused, and the kind's principal is admitted (ChildKind::principal).
  • Each child's pair is fresh. Its far end is in that child alone, and a socketpair has no address another child could reach.
  • One ask in flight per kind. A second ask is answered 429 at once, and a publish asked while one runs is refused by the publish's own lock, so a script in a loop queues nothing. A child has 10 s to send an ask's headers.
  • The child router is POST /cms/api/publish and the editor's push routes (git::editor::push_routes), each in the site's PUSHES group, which a script and the terminal hold. Nothing else is on it.
  • ask(method, path) is the child's side: one request on the inherited descriptor (ROUTES_FD).

Files

  • crates/lichen-site/src/site_process/child_routes.rs — new: the socket per child, the router, the one-at-a-time layer, and the child's ask. Read it top to bottom.

Lives elsewhere

  • The permissions a child kind holds (TriggerPushToPds, TriggerPushToRemote and the Script and Terminal principals): #18. The publish run it reaches: lichen-site/src/publish/run.rs in #25. The push routes: git/editor.rs in #23.
  • Where a child is given its end (the spawn paths of scripts, engines and the shell): #26 (scripts), #36 (shell), and lichen-sandbox's ROUTES_FD, #17. The admin thread that serves it: #38.
  • The tests (site_process__child_routes.rs, e2e) are in the base commit.

Category: The child-routes socket: what a credential-less child may ask Size: 1 file, +329/−0 Rounds: round 0 at b66397c0 (new in this round). Plans and ledger: FULL-SITE-PROCESS-2026-10-25.md (part 3, "How children reach the site's routes"; O3, O4; units 3f and 6g) with FULL-SITE-PROCESS-U0-DESIGN-2026-10-26.md; lichen-builder 6g (e665510d). Inline #[cfg(test)] modules: none. child_routes.rs points to a test file with #[path]. Bucket moves: a new subject in this round, given a PR of its own: the per-child route socket. It belongs beside the site process (#19), but it sits on top of the stack: Tangled cannot retarget a PR, so a PR inserted lower would make the one above it show the inserted commit. Round 1: none: new in this range.

This pull request has no versions submitted yet.