diff --git a/frontend/packages/swarm-ui/src/pages/LinkMatrixAccountForm.tsx b/frontend/packages/swarm-ui/src/pages/LinkMatrixAccountForm.tsx index 081c0b81..e27f5750 100644 --- a/frontend/packages/swarm-ui/src/pages/LinkMatrixAccountForm.tsx +++ b/frontend/packages/swarm-ui/src/pages/LinkMatrixAccountForm.tsx @@ -1,17 +1,11 @@ -// — writes a matrix account credential for one -// agent into the swarm secret store, in one of two modes (mirrors -// swarm-controller's `PutMatrixAccountRequest`): -// token — paste an already-obtained bearer token, optional homeserver. -// password — user id + password; swarm-controller logs into the -// (required, here) homeserver itself and stores the token -// that comes back. The password is sent once, over this -// PUT, straight to swarm-controller — never held here past -// the request, never sent to the hive. -// PUTs `/api/hives/{hive}/agents/{agent}/matrix-accounts/{account}` — -// 200 (`{ user_id? }`) on success, 400/503/500 on the documented failure -// arms — all handled generically via `readApiError`/`ApiErrorPanel`, -// same as every other form here, since the response is `problem+json` -// regardless of which arm fired. +// — writes a matrix account credential (token + +// optional homeserver) for one agent into the swarm secret store. +// PUTs `/api/hives/{hive}/agents/{agent}/matrix-accounts/{account}` per +// the contract atlas posted on the OpenBao swarm-secret-store adoption +// issue: `{ token, homeserver? }` body, 200 on success, 400/503/500 on +// the documented failure arms — all handled generically via +// `readApiError`/`ApiErrorPanel`, same as every other form here, since +// the response is `problem+json` regardless of which arm fired. // // No "linked accounts" list to show first: no route exposes one (a // credential store shouldn't hand a secret back out anyway), so this is @@ -21,6 +15,12 @@ // mara's rulings on that issue — there's no assignment step here yet, // just the write. // +// Deliberately built against the contract before the endpoint exists +// (atlas: "it does not change when the implementation lands") — until +// item 2 merges this 404s, same as any other page pointed at a route +// that isn't live yet. Nothing here depends on the backend being up to +// be correct. +// // Rendered inside a `Dialog` from `AgentsPage`, one per row — same // mount shape as `CreateAgentForm`, own file for the same reason (a // multi-field form with real submit-state handling is more than @@ -31,12 +31,9 @@ import { ApiErrorPanel } from "@hive/shared/api-error-panel.js"; import { readApiError, type ProblemDetails } from "@hive/shared/api-error.js"; import { Panel } from "../ui/panel/Panel.js"; import { TextField } from "../ui/text-field/TextField.js"; -import { SelectField } from "../ui/select-field/SelectField.js"; import { Button } from "../ui/button/Button.js"; import "./LinkMatrixAccountForm.css"; -type Mode = "token" | "password"; - // The store's own key-space, not `hive_types::Ident` — atlas's measured // gap on the issue: an agent name is an `Ident` (lowercase-only) but an // account name is a bare attrset key under `matrixAccounts`, so it @@ -48,18 +45,9 @@ const ACCOUNT_PATTERN = "[A-Za-z0-9_\\-]{1,63}"; type SubmitState = | { status: "idle" } | { status: "submitting" } - // `userId` is set in password mode (the server resolves it from the - // login response) and `undefined` in token mode — see - // `PutMatrixAccountResponse`'s own doc for why token mode doesn't - // spend a round trip resolving one. - | { status: "done"; userId?: string } + | { status: "done" } | { status: "error"; problem: ProblemDetails }; -const MODE_OPTIONS = [ - { value: "token", label: "paste a token" }, - { value: "password", label: "log in with a password" }, -]; - export function LinkMatrixAccountForm({ hive, agent, @@ -68,10 +56,7 @@ export function LinkMatrixAccountForm({ agent: string; }) { const [account, setAccount] = useState(""); - const [mode, setMode] = useState("token"); const [token, setToken] = useState(""); - const [userId, setUserId] = useState(""); - const [password, setPassword] = useState(""); const [homeserver, setHomeserver] = useState(""); const [result, setResult] = useState({ status: "idle" }); @@ -84,43 +69,26 @@ export function LinkMatrixAccountForm({ { method: "PUT", headers: { "content-type": "application/json" }, - body: JSON.stringify( - mode === "token" - ? { - mode, - token, - // Omitted rather than sent empty — the contract marks - // it optional in token mode, and an empty string - // isn't "no homeserver", it's a homeserver named "". - homeserver: homeserver.trim() || undefined, - } - : { - mode, - user_id: userId, - password, - // Required in password mode — the field below enforces - // that before this branch is ever reachable. - homeserver: homeserver.trim(), - }, - ), + body: JSON.stringify({ + token, + // Omitted rather than sent empty — the contract marks it + // optional, and an empty string isn't "no homeserver", it's + // a homeserver named "". + homeserver: homeserver.trim() || undefined, + }), }, ); if (!r.ok) { setResult({ status: "error", problem: await readApiError(r) }); return; } - const body = (await r.json().catch(() => ({}))) as { - user_id?: string; - }; - setResult({ status: "done", userId: body.user_id }); - // Secrets cleared on success — nothing left needing them in the - // form once the store holds the derived credential, and a secret - // sitting in a field after the action that used it is exactly the - // kind of stale-credential risk the whole store exists to avoid. - // Account name kept, so the success message below reads against - // what actually landed. + setResult({ status: "done" }); + // Token cleared on success — nothing left needing it in the form + // once the store holds it, and a secret sitting in a field after + // the action that used it is exactly the kind of stale-credential + // risk the whole store exists to avoid. Account name kept, so the + // success message below reads against what actually landed. setToken(""); - setPassword(""); } catch (err) { setResult({ status: "error", problem: { detail: String(err) } }); } @@ -150,54 +118,20 @@ export function LinkMatrixAccountForm({ required onInput={setAccount} /> - setMode(v as Mode)} + - {mode === "token" ? ( - - ) : ( - <> - - - - )}