feat(proxy): Console proxy setup page and CLI parity (#1873) #1943

Merged
jason.woltje merged 2 commits from proxy-ui into refactor 2026-11-11 22:37:14 +00:00
Owner

Model proxy setup in the Console (#1873): one Proxy setup panel on Settings → Model proxy takes the instance owner from nothing to a running proxy, with the init inside the page.

  • Status overview with one next-step button per state: fetch, init-lock clear or wait, init repair, init, unit install/start/restart, fence clear, accounts.
  • Fetch runs in the background and checks archive, panel and executable against the pinned SHA-256 (CLIProxyAPI 8.0.42, panel 1.26.7). The receipt carries every hash.
  • Init: by default the bus generates the key and never returns it. A pasted key is offered only on loopback or HTTPS (proxy-key-transport otherwise). Init is exclusive-create.
  • Unit render, install, start, stop, restart. Health means the unit's process tree listens on the configured port.
  • Fence clear needs a restart the page confirmed (new pid, started after the fence, listening). The bus re-proves it before clearing; without it the clear refuses proxy-restart-required.
  • Init-lock clear only when every bus is stopped and no proxy files exist.
  • Account and model panels are unchanged; they hide with a setup note while the proxy does not answer.
  • Every action appends a receipt to <dataRoot>/state/proxy-admin.jsonl; the page shows the last ten.
  • Routes /api/proxy/admin/* mount only on a Console with a system config and --dev-local-owner or SSO, behind the existing proxy route checks. Everyone else gets human-required.
  • CLI parity: mosaic proxy status, unit render|install|start|stop|restart, init --generate-key, fence clear --restart, init-lock status|clear. New verbs refuse agent shells and --tester.
  • Every new refusal code has a refusal-table entry with a next step.

Acceptance: page and CLI flows run end to end on scratch instances up to a running proxy with a routed model (screenshots 1440x900 light and 390x844 dark). Agent, tester and cross-origin refusals on every new route and verb. Redaction sentinels absent. New tests fail on BASE.

Not met here: a chat reply through the proxy. The API key upstream is a fixed address, and the OAuth accounts need real credentials. The owner does that leg on the dev Console with their own account.

Tests: lane gate 519 files, 5171/0, 5 environment-gated skips. Lead check: 128 files on 35c125fc1 (model-proxy, every proxy, console-bus, refusal and cli.mjs reader, agent-guard), 1477/0, 1 opt-in skip (FED R7).

Review: build (Opus) changes 3, security (daybreak-blue) changes 1; P2s and P3s fixed with tests; security re-check approve. Build P1 (chat leg) deferred as above.

Deferred: a loopback-only upstream override for a scratch instance; accounts and models CLI verbs; fence clear --proxy-restarted stays self-attested; own proxy per organization not built (ruling 8); a live uncertain fence was not induced.

Model proxy setup in the Console (#1873): one Proxy setup panel on Settings → Model proxy takes the instance owner from nothing to a running proxy, with the init inside the page. - Status overview with one next-step button per state: fetch, init-lock clear or wait, init repair, init, unit install/start/restart, fence clear, accounts. - Fetch runs in the background and checks archive, panel and executable against the pinned SHA-256 (CLIProxyAPI 8.0.42, panel 1.26.7). The receipt carries every hash. - Init: by default the bus generates the key and never returns it. A pasted key is offered only on loopback or HTTPS (`proxy-key-transport` otherwise). Init is exclusive-create. - Unit render, install, start, stop, restart. Health means the unit's process tree listens on the configured port. - Fence clear needs a restart the page confirmed (new pid, started after the fence, listening). The bus re-proves it before clearing; without it the clear refuses `proxy-restart-required`. - Init-lock clear only when every bus is stopped and no proxy files exist. - Account and model panels are unchanged; they hide with a setup note while the proxy does not answer. - Every action appends a receipt to `<dataRoot>/state/proxy-admin.jsonl`; the page shows the last ten. - Routes `/api/proxy/admin/*` mount only on a Console with a system config and `--dev-local-owner` or SSO, behind the existing proxy route checks. Everyone else gets `human-required`. - CLI parity: `mosaic proxy status`, `unit render|install|start|stop|restart`, `init --generate-key`, `fence clear --restart`, `init-lock status|clear`. New verbs refuse agent shells and `--tester`. - Every new refusal code has a refusal-table entry with a next step. Acceptance: page and CLI flows run end to end on scratch instances up to a running proxy with a routed model (screenshots 1440x900 light and 390x844 dark). Agent, tester and cross-origin refusals on every new route and verb. Redaction sentinels absent. New tests fail on BASE. Not met here: a chat reply through the proxy. The API key upstream is a fixed address, and the OAuth accounts need real credentials. The owner does that leg on the dev Console with their own account. Tests: lane gate 519 files, 5171/0, 5 environment-gated skips. Lead check: 128 files on 35c125fc1 (model-proxy, every proxy, console-bus, refusal and cli.mjs reader, agent-guard), 1477/0, 1 opt-in skip (FED R7). Review: build (Opus) changes 3, security (daybreak-blue) changes 1; P2s and P3s fixed with tests; security re-check approve. Build P1 (chat leg) deferred as above. Deferred: a loopback-only upstream override for a scratch instance; accounts and models CLI verbs; `fence clear --proxy-restarted` stays self-attested; own proxy per organization not built (ruling 8); a live uncertain fence was not induced.
jason.woltje added 2 commits 2026-11-11 22:37:11 +00:00
One Proxy setup panel on the Model proxy settings page takes an owner from
nothing to a running proxy: status with one next-step button per state, the
pinned fetch with hash checks, progress and a receipt, init with a
bus-generated key (a pasted key only over loopback or HTTPS, with a
confirmation), unit render/install/start/stop/restart with health, a fence
clear that the bus re-proves against a confirmed restart, and a stale init
lock clear that names its blockers. Own proxy per organization shows as not
built.

New Console routes under /api/proxy/admin/ use the existing owner proxy
checks; agents, testers and grant holders get human-required. New bus verbs
proxy.init {generate:true} and proxy.fence.clear. Receipts go to
<dataRoot>/state/proxy-admin.jsonl with labels and key ids only. Every new
refusal code has a refusal-table entry.

CLI: mosaic proxy status, unit render|status|install|start|stop|restart,
init --generate-key, fence clear --restart, init-lock status|clear; proxy
fetch keeps its stdout and adds progress and the receipt.

Page fix found in the end-to-end run: a stopped proxy hides the account
panels until the service answers. (The catalogue switch label fix found in
the same run landed upstream as D3 P0-4.)
Security review:
- Release verification cache keys on ctime as well as mtime, in
  nanoseconds. A same-size rewrite with mtime set back now re-hashes and
  reports proxy-install-invalid.

Build review:
- The setup page hides the account panels on any failed accounts read, not
  only proxy-down, and brings them back once the proxy answers.
- The organizations table shows a dash, not a made-up 0, when a bus does
  not answer or sends no model list (orgCatalogue in proxy-admin.mjs).
- A fence clear the bus did not answer keeps the confirmed restart for a
  retry.
- A fence with no readable time names `mosaic proxy fence clear
  --proxy-restarted` on the page, in the refusal table and in the README.
- CLI `init --generate-key` goes through the setup controller and writes
  the same init receipt as the page.
- Status carries the last ten receipts, so the page shows them after a
  reload. An initialized proxy keeps the init form folded.
- README: proxy-admin-busy is per process; the cross-process locks that
  serialize the writes are named.
jason.woltje merged commit 75f6d5533a into refactor 2026-11-11 22:37:14 +00:00
Sign in to join this conversation.