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

full 16: Front server: the dashboard API, the CLI and the desktop #79

targeting full/15-front-state
Open opened by and assigned to notplants-bot.bsky.social
targeting full/15-front-state

The dashboard's JSON API (lichen-server/src/api.rs), and the CLI's and desktop app's entry points. Every API route now sits in a permission group, and its errors share one shape. The site acts it offers are all asked of the site's process: its admin thread does the hub's (compact, force pull, force push, compact-all, the remote and sync settings, the publish), and the rest go to the site as ordinary requests, with the admitted identity. The lichen executable also starts site processes, runs the hub's pre-receive check and the sign-in render child, and empties its environment at startup, giving the user's own environment back only to the tools it runs for the user.


AST-verified changes

  • lichen-cli/src/commands/mod.rs → commands.rs, lichen-server/src/desktop/mod.rs → desktop.rs and single/mod.rs → single.rs: three of OPERATOR-REVIEW-FIXES U1's 19 foo/mod.rs renames (f6a10c32). Run id not recorded: "3004 items, 48 moved, 69 carried, 19 renamed, 2 visibility as mapped, 233 module declarations" (lichen-builder.md 2087); adversary notify-abab368a, same counts.
  • emit_settings_saved and edit_iroh_peers_doc from api.rs to lichen-site's settings/edit.rs (#37), with eight settings helpers from utils.rs (#33) (P2c-2b commit 1c, 85a5e79e). Run id not recorded: "10 moved, 3 visibility" (lichen-builder.md 2352); adversary 10/3.
  • The path rewrites of SECURITY-FOLDER-AND-PRINCIPALS units 1 and 2 in this PR's files (crate::site_area → crate::admin_area, crate::access → crate::security::access, and the other security:: paths), which those checks cover (unit 1 notify-eebdd32e, unit 2 adversary notify-020eb199, both equal, errors 0), with the rustfmt rewraps after them (d6c25912, bdaa795b), proven by cargo fmt.

Roughly 170 of this PR's 1,637 changed lines are code these moves carried verbatim, all in api.rs. With rename detection the renames show only their changes.

On this forge the 3 renamed files here show as a whole deletion and a whole addition, so its diff reads 1,683 changed lines; with rename detection (git diff -M full/15-front-state full/16-api-cli) it is 1,637.


The dashboard API (api.rs, DASHBOARD-REACT unit 1). The React dashboard and a custom dashboard (through lichen-ts/dashboard) call these routes on the dashboard host:

  • Every route is in its permission group (site(&[ReadSite]), account(&[ManageDeployKey]), …). A handler reads the site its group admitted (admitted_site) instead of checking for itself, so path_acl_guard and require_session_site are gone.
  • Errors are in one shape. An unknown /api path is a 404 in that shape.
  • Site acts asked of the site process's admin thread (FULL-SITE-PROCESS 6c–6e, through front_seams): compact, compact-all, force pull, force push (whose answer is the push's own), backup status (STC-BACKUP1), the remote and sync settings, the publish key and trigger-publish. The DNS checks and the edit-host handoff (H2a: browser sessions only) stay the front server's. Setting a deploy key copies it into each of the owner's sites' areas before it answers (4f1), and a create answers 409 for a folder an unfinished delete left.
  • Site acts forwarded to the site's process (site_act): auto-save, iroh peers, collaborators and revert. They go as ordinary requests to /cms/api/…, with the admitted identity in x-lichen-identity and no admin connection (SITE-FRONT-BOUNDARY 11a1).
  • POST /api/auto-pull pulls the user's auto-pulling sites; the dashboard's GET only renders (H3: a GET never acts).

The CLI (crates/lichen-cli/):

  • main.rs dispatches, before anything else: the hub's pre-receive check (SITE-FRONT-BOUNDARY unit 4), --build-id, and the sign-in pages' render child (DASHBOARD-REACT unit 4). It then calls lichen_env::init(), which reads the environment once and empties it but for a keep-list (CHILD-ENV-CLEAR E2). It registers its own executable for site processes (by inode on Linux, so an in-place upgrade does not replace it), and a hidden lichen site serve runs a site process, started by lichen_site::site_process::start::site_process_main: its admin thread first, then the narrowing, then the runtime (FULL-SITE-PROCESS unit 1, #38). lichen ask METHOD PATH lets a child ask for a publish or a push on its child-routes socket, holding no credential (6g, #40).
  • user_env.rs — new: the CLI's own tools (git, cargo install, the browser) run with the environment the user started lichen with, the plan's one named exception. commands/*.rs use it.
  • config.rs, server.rs read variables through lichen-env, and HOME falls back to the password database.
  • client.rs shows the message from the API's error shape. oauth_server.rs puts its loopback callback in the public group.

The desktop app (crates/lichen-tauri/): main.rs serves a site process when the desktop server launches one; build.rs allows cargo's environment at build time. lichen-server/src/desktop/server.rs fills the new settings with desktop defaults. cli.rs and single/cli.rs follow the crate rename.

Files

  • crates/lichen-server/src/api.rs — the dashboard API. Read this first.
  • crates/lichen-cli/src/main.rs, user_env.rs (new), commands.rs, commands/{auth,git,sync,update}.rs, config.rs, client.rs, oauth_server.rs, server.rs, Cargo.toml (adds lichen-env, libc and a test-routes feature).
  • crates/lichen-tauri/src/main.rs, build.rs, Cargo.toml.
  • crates/lichen-server/src/cli.rs, single.rs, single/cli.rs, desktop.rs, desktop/server.rs.

Lives elsewhere

  • What the API acts on: state.rs, server_settings.rs: #31. The rewrites behind compact, force pull and force push: #23. The publish: #25.
  • The dashboard's pages and /api/dashboard, /api/account (dashboard.rs): #33. Host routing and the handoff's receiving end: #30.
  • The site acts' routes and groups on the site side (acts.rs): #19.
  • contract/dashboard-api.json, the hand-written contract a test holds this router to, and the React dashboard are in the base commit.
  • Tests (tests/dashboard_api.rs, the CLI's tests, e2e) are in the base commit.

Category: Front server: the dashboard API, the CLI and the desktop Size: 21 files, +1,016/−621 Rounds: round 0 at stack ae42e3c0; round 1 at 6b650b2a (SECURITY-FOLDER-AND-PRINCIPALS): path rewrites in api.rs. Read that round in its interdiff: https://tangled.org/notplants-bot.bsky.social/lichen.page.october/pulls/32/round/1/interdiff; round 2 at b66397c0 (FULL-SITE-PROCESS): api.rs asks the site process's admin thread for the hub's acts and status, the remote and sync settings and the publish key (through front_seams), copies a new deploy key into each site's area, and answers 409 for a leftover folder; the CLI starts a site process through site_process_main and adds lichen ask. Read this round in its interdiff: https://tangled.org/notplants-bot.bsky.social/lichen.page.october/pulls/32/round/2/interdiff Plans and ledger: FULL-SITE-PROCESS-2026-10-25.md (1, 4f1, 6c–6e, 6g); DASHBOARD-REACT-2026-10-07.md (unit 1; DASHBOARD-REACT-U1-DESIGN-2026-10-17.md), ADMIN-EDIT-HOST-SPLIT-2026-10-13.md (H2a, H3), SITE-FRONT-BOUNDARY-2026-10-17.md (units 4, 8, 11a1, 11e), PER-SITE-PROCESS-2026-10-09.md (P2c-2b, P4-1), CHILD-ENV-CLEAR-2026-10-08.md (E2), OPERATOR-REVIEW-REVISIONS-2026-10-13.md (N8), OPERATOR-REVIEW-FIXES-2026-10-07.md (U1); lichen-builder.md 2087, 2352. Inline #[cfg(test)] modules: api.rs (structured_settings_edit_tests). Six more files point to a test file with #[path]. Bucket moves: none against round 1. Split out of round 1's front-state PR: the API and its clients here, the state in #31. Round 1: #11 (Front server: state, the dashboard API, CLI and desktop) covered api.rs, desktop/server.rs, the CLI's main.rs, client.rs, oauth_server.rs, server.rs and lichen-tauri's main.rs from 0b92cb61; the rest is new in this range.

This pull request has no versions submitted yet.