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

full 23: Every sandbox in one place: how a site process starts its children #86

targeting full/22-admin-thread
Open opened by and assigned to notplants-bot.bsky.social
targeting full/22-admin-thread

Every sandbox lichen sets is now data in one module, lichen-site/src/sandbox/spawns.rs. It holds the site process's own sandbox and the narrow sandbox its main runtime and children hold. It also holds the spawns the site's own code starts (the hub's receive and fetch, the backup's read, fetch and restore, a push to a remote, a wisp deploy) and the front server's sign-in render. A structure test holds that nothing else builds a sandbox spec, a confine policy, a Landlock ruleset or a seccomp filter.


AST-verified changes

  • FULL-SITE-PROCESS 5a2 (#1647 on lichen.page.review, 765209c7 → 8d7bb2b4, map machine-docs/reports/fsp-5a2/move-map.json): SITE_MAX_PROCESSES, hub_push_spec, wisp_spec and on_path from lichen-server's site_process/front.rs (#19) to sandbox/spawns.rs, each made pub. Run notify-73fbe4f9: "equal=True, items 5557/5557, moved 4, stayed 5553, visibility 4", both plants caught. Adversary rerun: "equal=True, 5557/5557, moved 4" (notify-4a18fbec).
  • FULL-SITE-PROCESS 6a (#1651, deef05fc → 0b71076c, map machine-docs/reports/fsp-6a/move-map.json): site_spec, upload_pack_spec, restore_spec, backup_fetch_spec, hub_receive_spec and hub_fetch_spec from lichen-server's site_process/front.rs (#19); SIGN_IN_RENDER_ADDRESS_SPACE and sign_in_render_spec from sign_in_render.rs (#33); and policy from lichen-site's permissions.rs (#18). Run notify-82fbca10: "equal=True: items 5581/5581: moved 9, stayed 5572; visibility_changes 8, every one listed; comments compared 4995". Adversary rerun: equal=True, 5581/5581, its plants caught (notify-ec60785b).

None of this PR's 498 changed lines can be skipped for these moves. The functions they carried were written after 09-23, so in this diff spawns.rs reads as new code. The moves show only that gathering them changed no item.


The module's own list is the place to start:

  1. The site process (site_spec): its folder and its admin area read-write, the allowance read-only, the system's code, TCP only through the egress, and its process cap (SITE_MAX_PROCESSES).
  2. The narrow sandbox (site_spec's narrow): what the site process's main thread takes before the main runtime starts (#38). It covers the site's folder, and of the admin area only the hub, read-only.
  3. A child's nested layer (D2): every ordinary child enters a Landlock domain of its own that restricts no path, only the scopes (no signal or abstract socket out of it), with no_new_privs. That layer is lichen-sandbox's (prepare_ordinary, the nest mode), and is named here.
  4. The opt-in (full-permissions-for-child-processes, in the admin area's settings.toml) lifts the narrow sandbox. The main runtime and its children then hold the site process's grants. A child's nested layer stays.
  5. The spawns of lichen's own code, each confined to what it touches: hub_receive_spec, hub_fetch_spec, upload_pack_spec, backup_fetch_spec, restore_spec, hub_push_spec, wisp_spec, sign_in_render_spec.
  6. policy compiles a list of Permissions to paths.

Files

  • crates/lichen-site/src/sandbox/spawns.rs — new: the above. Read it top to bottom; it is meant to be read as the table of lichen's sandboxes.

Lives elsewhere

  • The mechanism that applies them (Landlock, seccomp, the sandbox mode, nest): lichen-sandbox, #17. The site's interface to it (lichen-site/src/sandbox.rs) and command/tokio_command: #17.
  • What each kind of spawn may do (Permission, the lists, child_limits): #18.
  • Where the site process is launched with site_spec (site_process/front.rs): #19. Where the narrowing is applied (site_process/start.rs): #38.
  • The spawn goldens and the structure test (every_sandbox_is_defined_in_one_module) are in the base commit.

Category: Every sandbox in one place: how a site process starts its children Size: 1 file, +498/−0 Rounds: round 0 at b66397c0 (new in this round). Plans and ledger: FULL-SITE-PROCESS-2026-10-25.md (part 1, "One place starts every child"; units 5a2 and 6a; the operator, 2026-10-26: "ideally that is all set simply in one place") with FULL-SITE-PROCESS-U0-DESIGN-2026-10-26.md (D2); lichen-builder 5a2 and 6a rows (2026-10-26T18:20Z, 19:53Z); lichen-adversary 2026-10-26T18:37Z, 20:05Z. Inline #[cfg(test)] modules: none. Bucket moves: a new subject in this round, given a PR of its own: the children's spawn path. It belongs beside the sandbox (#17) and permissions (#18), 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.