Commit graph

9 commits

Author SHA1 Message Date
Bryan Helmkamp
537a5125cb
feat(auth): tighten server auth surface with single origin
Implements plan: single origin, drop CLI preflight, gate demo toggle.
Removes loopback client target and CLI auth config preflight endpoint;
adds canonical_origin module on the server; regenerates SPA and TS API
client.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:38:31 -04:00
Bryan Helmkamp
5958470a11
plan 2026-04-19 15:18:22 -04:00
Bryan Helmkamp
224673bdf6
docs(install): address sixth review pass on web-install spec
Two fixes:

P0 — Container packaging blocks install mode. The published Dockerfile
bakes /etc/fabro/settings.toml and sets FABRO_CONFIG, which under the
explicit-config carveout means containers would never enter install
mode. v1 must change the Dockerfile: drop the baked settings file,
drop FABRO_CONFIG, set FABRO_STORAGE_DIR=/storage, and persist
~/.fabro across container restarts (recommendation: move FABRO_HOME
into a subdirectory of the /storage volume so one mount covers both
config and data). Spelled out as load-bearing v1 implementation work
under Orchestration config updates. New decision-log row #24.

P2 — Force-foreground decision was not carried through to all sections.
Two leftover references to a `__serve` daemon child contradicted the
"install mode never daemonizes" decision — one in the local-lifecycle
prose, one in the manual smoke test. Updated both to describe the
foreground process exiting cleanly. Decision-log row for #21 also
updated to reflect that the install process IS the operator's `fabro
server start` invocation under foreground mode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
d34f338e33
docs(install): address fifth review pass on web-install spec
Two fixes:

P1 — Install token surfacing in local daemon mode. Today's
`fabro server start` daemonizes by default; the daemon parent prints
its own summary but the child's stderr (where the install token would
print) is redirected to server.log. Operator wouldn't see the token
without tail-ing the log file. Decision: install mode forces foreground
regardless of how `fabro server start` was invoked; the token then
lands on the operator's terminal directly. Documented as "--foreground
is implicit during install." Daemon path is bypassed entirely for
install mode; restored on the supervisor restart.

P2 — `--no-web` contract hole. The flag is accepted by `server start`
and `server restart` but the spec didn't say what install mode does
with it. Decision: ignore during install with an explicit stderr
warning ("will be respected on next start"); respected after the
supervisor restart. Rejecting would force supervised-deployment
operators to either drop the flag or `docker exec` to run the CLI
wizard, defeating the point. Warning makes the override visible.

Added integration tests for both behaviors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
d21d9fa62f
docs(install): address fourth review pass on web-install spec
Three more fixes (all P2):

P2 — Goal wording said "using the same persistence helpers" but the
body explicitly carves out a separate install-mode vault path. Reword
to "same on-disk state, sharing the TOML/env primitives" so the
implementer isn't misled about how much of the CLI path is reused.

P2 — Summary said only `fabro server start` enters install mode but
the process model says start and restart. Reconcile: name both
commands explicitly in the summary.

P2 — Test plan covered the GitHub App `state` rejection path but not
the happy-path roundtrip (POST /install/github/app/manifest → GET
/install/github/app/redirect with stubbed conversion). Add an
integration test that covers the riskiest new path: code-exchange
wiring, session population, redirect-with-token handling, and that
the canonical-URL ordering decision actually flows through to the
manifest.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
0a576a5f74
docs(install): address third review pass on web-install spec
Three more fixes:

P0 — Local restart UX. Today's `fabro server start` does not stay
around to supervise the `__serve` child it spawns (`start.rs:318`), so
no auto-restart happens locally after `/install/finish` exits. Spec the
two cases honestly: supervised deployments rely on the supervisor;
local laptops show the operator a "run `fabro server start` to launch
your configured server" message after a 30s polling timeout. A built-in
local supervisor is named as a follow-up. Updated the manual-test
section to cover both cases and the orchestration-docs section to
detect supervised vs. local at boot time.

P1 — Auto-start callers must not enter install mode. `connect_server`
→ `connect_api_client_bundle` → `start::ensure_server_running_for_storage`
is used by `run attach`, `server runs`, etc. Add an explicit *Auto-start
callers* subsection and a new decision: only the explicit `fabro server
start` (or `restart`) command enters install mode. Auto-start callers
fail with a clear "configure first" message pointing the operator at
either `fabro server start` or `fabro install`.

P2 — Process-model rationale corrected. The previous draft claimed the
existing dispatch path "would error on missing settings.toml" but that
is false: `user.rs:77` returns defaults, `serve.rs:820-824` falls back
to a Unix socket, and `tests/it/cmd/server_start.rs:111` is a passing
test of `fabro server start` with no config. Reworded to say what is
actually true — without the fork, `fabro server start` cheerfully boots
a non-functional default server, and install mode displaces that
default. Summary line now mentions the explicit-config caveat too.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
d70bc7a166
docs(install): address second review pass on web-install spec
Five more fixes:

P0 — Reorder wizard: Server config now precedes GitHub. The GitHub
manifest bakes <canonical_url> into redirect_url and callback_urls;
creating the App with a misdetected URL is a real-world side effect we
cannot unmake on github.com.

P0 — `persist_install_outputs` cannot be reused as-is from install
mode. Its vault path goes through `connect_api_client(storage_dir)`,
which calls back into the install-mode server itself (which doesn't
mount /api/v1/*) and would 404. Add an explicit decision: install mode
writes vault secrets directly to disk via Vault::load(...).set(...),
the same pattern persist_github_install_changes already uses. TOML and
env-file helpers remain reusable.

P1 — Bootstrap fork narrowed. Install mode triggers only when no
explicit --config or FABRO_CONFIG was provided AND the default
~/.fabro/settings.toml is absent. A typo in --config must error, not
silently install on top of the wrong target. Matches the asymmetry the
existing config loader already enforces (user.rs:81-112).

P1 — Stop overpromising rollback. The existing helper restores
settings.toml on vault failure but leaves server.env in place (verified
by install.rs:2910). Spec out the actual partial-state semantics for
v1, justify why it's acceptable (env keys are deterministic and
idempotent on retry), and call atomic rollback a deliberate follow-up.

P2 — On-disk layout corrected. Vault path is
<storage_dir>/vaults/default/secrets.json (storage.rs:38), not
<storage_dir>/secrets/.... Added the home-level dev-token file the CLI
also writes (install.rs:1994-1999) so parity is real.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
7b9c652548
docs(install): address plan review on web-install spec
Five fixes against the v1 spec:

P0 — Reconcile GitHub App callback flow with the CLI's actual
mechanism: manifest `redirect_url` (not `callback_urls`) carries the
post-creation handoff via browser 302; the install endpoint is renamed
to `/install/github/app/redirect` and authorized by OAuth `state`
because GitHub strips Authorization across redirects.

P1 — Bootstrap fork moves from "precheck inside serve" to the dispatch
layer, since today's `commands::server::dispatch` loads settings before
`serve` is invoked. Spec out the install bootstrap path explicitly,
including skipping the eager dev-token / session-secret creation.

P1 — Clarify that the same `fabro-web` bundle hosts the wizard via a
server-injected `window.__FABRO_MODE__` flag in `index.html` controlling
which router tree mounts at boot. Without this, existing route loaders
that call `/api/v1/auth/*` would throw before the install UI renders.

P2 — Correct the dev-token path to `<storage_dir>/server.dev-token`
(matching `Storage::server_state().dev_token_path()`).

P2 — Resolve the dev-token "never exposed to the client" contradiction:
JWT keys and session secret stay on the server; the dev token is
returned in the `/install/finish` response so the operator can copy it.

P2 — Note that the existing OpenAPI conformance test only covers
`build_router(...)` and would silently miss install drift. Spec the
expansion: split spec iteration by `install` tag, route to the
appropriate router, and verify cross-mounting is rejected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
5520785723
docs(install): spec the web-based install wizard
Captures the design for browser-driven first-run configuration as an
alternative to `fabro install`. When `fabro server` boots without
`~/.fabro/settings.toml`, it enters install mode, prints a one-time
token, and serves a wizard from the existing `fabro-web` bundle.
Reaches the same on-disk end state as the CLI, then exits cleanly so
the supervisor restarts into normal mode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00