docs: WebUI preview brief, signed-in read-only Console behind the edge proxy
Mos approved the cuts 2026-10-11: forward auth at the edge, a user unit beside the bus, a preview hostname, read-only. No code until Jason answers Q91 (amending lead decision 48). Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,106 @@
|
|||||||
|
# WebUI preview behind sign-in (2026-10-11)
|
||||||
|
|
||||||
|
Status: written by Sage, lead. It follows `docs/plans/BRIEF-TEMPLATE.md`.
|
||||||
|
One row. No code starts until Jason answers Q91 (amending lead decision
|
||||||
|
48 for a signed-in preview reachable beyond localhost). Mos relays the
|
||||||
|
answer. If the ruling narrows or changes what follows, this brief is
|
||||||
|
amended first.
|
||||||
|
|
||||||
|
## WebUI preview: a signed-in, read-only Console behind the edge proxy
|
||||||
|
|
||||||
|
### Problem
|
||||||
|
|
||||||
|
Jason asked for an ETA for the refactor WebUI at mosaic.woltje.com. Today
|
||||||
|
the Console can't be reached from anywhere but the host it runs on, by
|
||||||
|
design:
|
||||||
|
|
||||||
|
- `startServer` refuses to bind to a non-loopback address
|
||||||
|
(`packages/webui/src/serve.mjs:82`) and answers 403 to any request whose
|
||||||
|
Host isn't loopback on its own port (`serve.mjs:92`). A reverse proxy
|
||||||
|
that forwards the public Host is refused.
|
||||||
|
- The Origin check (`serve.mjs:96`) compares against `http://<Host>`, so a
|
||||||
|
browser on `https://<public name>` is refused as cross-origin.
|
||||||
|
- There is no sign-in. Anything that connects to the port reads what a
|
||||||
|
reader capability reads (`packages/webui/README.md`, the paragraph on
|
||||||
|
the bus views), and the README forbids a public proxy.
|
||||||
|
- Two routes write: POST `/api/seen` and `/api/reply` go to the board.
|
||||||
|
- Nothing runs the Console as a service. It is a foreground `serve`.
|
||||||
|
|
||||||
|
Mos approved these cuts for the preview (2026-10-11): sign-in at the edge
|
||||||
|
through Pocket ID forward auth, not login code in the Console; a systemd
|
||||||
|
user unit beside the bus; a preview hostname, so the old build at
|
||||||
|
mosaic.woltje.com stays; read-only; not held for S7 (row 42) or Gate E
|
||||||
|
(row 5). ops-01 owns the Pocket ID client, the DNS name, TLS, the proxy
|
||||||
|
and the route from the edge to this host. Jason approves that route
|
||||||
|
before anything is served.
|
||||||
|
|
||||||
|
### Owner and reviewer
|
||||||
|
|
||||||
|
Owner: Dewey, who owns the WebUI, after their row 59 review. Reviewers:
|
||||||
|
Darkwing and Filbert.
|
||||||
|
|
||||||
|
### Files owned
|
||||||
|
|
||||||
|
- `packages/webui/src/serve.mjs`, `packages/webui/src/cli.mjs`,
|
||||||
|
`packages/webui/README.md` and `packages/webui/tests/`
|
||||||
|
- a new `scripts/webui-service.sh` and its unit template, beside
|
||||||
|
`scripts/bus-service.sh` and `packages/cli/systemd/mosaic-bus.service.in`
|
||||||
|
- the test for that script, in the package that holds the template
|
||||||
|
- `docs/TOOLS.md`, the new script's entry only. Row 70 also edits this
|
||||||
|
file; whichever lands second rebases on the first.
|
||||||
|
- `agents/dewey/work/queue-<row>/`
|
||||||
|
|
||||||
|
### What ships
|
||||||
|
|
||||||
|
A preview mode, off by default. Without its flags the Console behaves
|
||||||
|
exactly as today, and the existing tests show it.
|
||||||
|
|
||||||
|
- `serve --public-host NAME --auth-header HEADER --allow-user ID`, all
|
||||||
|
three or none. NAME is a hostname, no port or scheme. The bind stays
|
||||||
|
loopback; nothing here listens beyond it.
|
||||||
|
- In preview mode a request's Host must be NAME, or loopback on the
|
||||||
|
Console's port as today. An Origin, when sent, must be `https://NAME`
|
||||||
|
for a NAME request, and the loopback form for a loopback request.
|
||||||
|
- A NAME request must carry HEADER with a value equal to ID. Missing or
|
||||||
|
different answers 401 with no bus read made. Loopback requests are
|
||||||
|
unchanged, so the operator's own browser on the host still works.
|
||||||
|
- In preview mode every POST answers 403 `read-only`, whatever the Host.
|
||||||
|
`/api/seen` and `/api/reply` don't reach the board.
|
||||||
|
- Tests for each refusal: wrong Host, wrong Origin, missing header, wrong
|
||||||
|
user, a POST to each write route, and a partial flag set refused at
|
||||||
|
start. A test that the loopback path is unchanged in preview mode.
|
||||||
|
- `scripts/webui-service.sh render|install|uninstall|status` for a
|
||||||
|
`mosaic-webui.service` user unit, on the `bus-service.sh` pattern: a
|
||||||
|
template, write to a temp file then rename, `daemon-reload` only, no
|
||||||
|
start, no restart. It runs the board's `serve` and the Console's
|
||||||
|
`serve` with the preview flags (as one unit or two, the packet says
|
||||||
|
which and why), with values from flags or an env file the script names.
|
||||||
|
The env file holds no secret: the header name, the user id and the
|
||||||
|
hostname aren't secrets.
|
||||||
|
- The README replaces "Do not expose either unauthenticated server
|
||||||
|
through a public proxy" with what the preview mode requires of the
|
||||||
|
proxy: it strips HEADER from every client request and sets it only
|
||||||
|
after Pocket ID signs the user in, it preserves Host, it terminates TLS,
|
||||||
|
and it is the only thing that reaches the port from off the host. It
|
||||||
|
says plainly that any local process can still connect and send HEADER,
|
||||||
|
the same exposure the README already describes for the port.
|
||||||
|
- The packet runs the Console in preview mode with `curl` against
|
||||||
|
loopback, showing each refusal and one allowed read, with no network
|
||||||
|
beyond the host.
|
||||||
|
|
||||||
|
### Out of scope
|
||||||
|
|
||||||
|
- OIDC or login code in the Console; Pocket ID config; DNS, TLS, the
|
||||||
|
proxy and the route from the edge (ops-01).
|
||||||
|
- Resolving decisions or replying from the browser. REQ-DEC-3 keeps
|
||||||
|
resolution in the CLI; changing that is a ruling and its own row.
|
||||||
|
- Live-seat conversations (CHAT-07) and any board change.
|
||||||
|
- A container image, CI deploy, or changes to the bus unit.
|
||||||
|
- Installing or starting the unit on dragon-lin. Sage does that after the
|
||||||
|
row lands, only once Jason has ruled on Q91 and approved ops-01's route.
|
||||||
|
|
||||||
|
### Gate
|
||||||
|
|
||||||
|
Darkwing and Filbert approve on the row's issue naming the candidate
|
||||||
|
manifest. The webui, control-board and cli node suites and every
|
||||||
|
`scripts/test-*.sh` green on Sage's gate rerun.
|
||||||
Reference in New Issue
Block a user