Public UI behind forge sign-in (SPEC §8.3) #16
Loading…
Reference in a new issue
No description provided.
Delete branch "web-auth"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The UI and API leave the "trusted LAN" model: they are served publicly behind sign-in through the forge (SPEC §1, §7.1.1, new §8.3).
statevalue bound to a cookie and single-use. It requests only theread:userscope, and the user's token is dropped after one/api/v1/usercall.Secure; HttpOnly; SameSite=Lax). Only its SHA-256 is stored, inweb_sessions, with a TTL (default 7 days).Adminextractor for operator GETs. Cookie-authenticated non-GETs must carry anOrigin(orReferer) matchingexternal_url.Authorization: Bearer <forge PAT>. Agent tokens are refused there and never sent to the forge./healthz, the HMAC webhook,/agent,/api/artifacts/{hash},/git/(from #11), and/auth/*. A route-walking test checks that no other route answers an anonymous request with a 2xx.[auth]is required.disabled = trueexists for local runs and is refused unless the listener is on loopback. With sign-in enabled, startup requires httpsexternal_urlandagent_auth = "required". The module defaultslisten_addrto loopback.⚠️ Deploying this is a coordinated switch: every agent needs a token, and pixienix needs the OAuth app, the secrets and the nginx config first. See
docs/forgejo-setup.md.🤖 Generated with Claude Code
The control plane is served publicly behind one TLS proxy, so nothing is trusted for being on the network any more: - Sign-in: Forgejo's OAuth2 authorization-code flow with PKCE (oauth2 crate), `state` bound to the browser by a short-lived cookie. The token asks for read:user only, is used once for /api/v1/user and dropped. - Sessions: 256 random bits in a Secure/HttpOnly/SameSite=Lax cookie, only a SHA-256 kept (`web_sessions`, SPEC §9), absolute expiry, POST /auth/logout. - Scripts: `Authorization: Bearer <forge token>` resolved via /api/v1/user. - Reads mirror forge repo access, asked with the control plane's own token through the collaborator-permission endpoint and cached; unreadable graphs are 404s and lists are filtered in the query. Artifacts follow the repo that produced them; agents keep the upload token. - Acting needs `[auth].admins`: every non-GET behind the session gate, plus the `auth::Admin` extractor for operator GETs. Cookie state changes must come from external_url's origin. - `[auth]` is mandatory: forge login, or `disabled = true` on a loopback listener only (proxied requests refused). Login requires agent_auth = "required" and an artifact upload token. - NixOS module: controlPlane.auth.{clientId,clientSecretEnv,admins}, listen on 127.0.0.1:1337 by default. SPEC §1 non-goal and §7.1.1 rewritten, §8.3 added; forgejo-setup covers the OAuth application and the nginx site. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>CI failure is infrastructure (the drv push from the eval node raced
nix/dep/sourceon nuxbox), not this change.@krisbuild rerun
unknown merge-queue command
rerun.Reviewed across its merges: one sign-in gate over everything except the self-authenticating routes (
/healthz, HMAC webhook,/agent,/git/, artifacts,/auth/*); every non-GET needs an admin plus a same-origin check; enrollment listing/approval is admin-only; repo-scoped lists (graphs, merge queue) filter by what the forge lets the caller read. Client id/secret come from the environment. The socket-activation default now follows the loopbacklisten_addr(127.0.0.1:1337). CI green on this head.Deploy note: after this lands, a control plane without
[auth]refuses to start. The matching pixienix change is ready onkrisbuild-web-auth.@krisbuild r+
Removed from the merge queue: the merge conflicts in Cargo.lock, Cargo.toml, crates/kb-control-plane/Cargo.toml, crates/kb-control-plane/src/config.rs, crates/kb-control-plane/src/lib.rs, flake.nix.
Merged main (#13):
[auth]and[attic]coexist in config (both resolved and validated at load), the module keepsauth.*beside #13'sextraEnvironmentFiles/cachePush/attic.*, and the lockfile only adds this PR's crates. #13's token issuance inws.rsis unchanged. CI green on this head; priority so it lands before main moves again.Deploy note: after this lands, a control plane without
[auth]refuses to start; the matching pixienix change is ready onkrisbuild-web-auth.@krisbuild r+ p=5
Merged as
dd2dc7db65.