Skip to content

Commit 79f077f

Browse files
GottZclaude
andcommitted
docs: README — operator control plane (admin API + secrets + Svelte UI) now shipped
Both READMEs predated A17-A19 and described only ingest + the C2 channel. Reflect the bearer-authenticated operator control plane (cmd/admin) that is now built and live: admin API (device CRUD + command enqueue), encrypted AES-256-GCM secrets KV (fail-closed, master key off-disk in the public image), GET /api/events SSE, and the embedded Svelte 5 operator web UI (//go:embed; login + live roster + read-only degradation). Honest framing — the SPA shell + roster ship now; the feature pages (OTA/logs/telemetry/Berry/FaaS/Web-USB) mount in later waves. Also corrected the stale "a dedicated admin route lands later" note (POST /api/command shipped in A17). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e599ea7 commit 79f077f

2 files changed

Lines changed: 42 additions & 5 deletions

File tree

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Everything is developed in public.
1414
|---|---|
1515
| `documentation/` | **published** |
1616
| `firmware/` | **in progress** — networked run-cycle + recovery guard + Berry render/config engine + HOTP-authed C2 command channel |
17-
| `backend/` | **in progress** — TimescaleDB + Grafana + telemetry/OTA/log schema + ingest + HOTP-authed C2 command channel |
17+
| `backend/` | **in progress** — TimescaleDB + Grafana + telemetry/OTA/log schema + ingest + HOTP-authed C2 command channel, plus a bearer-authenticated **operator control plane** (admin API, encrypted secrets KV, embedded Svelte operator web UI) |
1818
| `tools/` | **started** — picpak-ops operator TUI + air-gap gate (on-device validation pending) |
1919
| `web-usb/` | not public yet |
2020

@@ -129,6 +129,14 @@ A full suite, built clean:
129129
- [x] [`backend/`](backend/) — self-hostable Docker backend: TimescaleDB + Grafana + the
130130
telemetry/OTA/log schema + legacy ingest, and the **C2 command channel** (per-device Berry
131131
command queue + per-device HOTP auth)
132+
- [x] **operator control plane** (in [`backend/`](backend/)) — a bearer-authenticated admin API in a
133+
process and address space **separate from the public ingest parser**: device CRUD + RCE-capable
134+
command enqueue, and an **encrypted secrets KV** (AES-256-GCM sealed; the master key is never on
135+
disk in the public image and the service fails closed without it). It serves an embedded
136+
**operator web UI** — a Svelte 5 SPA (`//go:embed`, one binary, no CORS): key login, a live device
137+
roster over server-sent events, and read-only degradation for non-admin keys. The feature pages —
138+
OTA rollout, log viewer, telemetry dashboard, Berry editor, FaaS editor, Web-USB onboarding —
139+
mount into this shell in later waves.
132140
- [x] [`tools/`](tools/) — host-side tooling: the **picpak-ops** operator TUI
133141
(build / flash / console / OTA / telemetry / logs) and the air-gap gate
134142

backend/README.md

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ Self-hostable telemetry / OTA / log backend for the open-picpak fleet. Go servic
55
ad-hoc plotting scripts.
66

77
> **Status:** TimescaleDB + Grafana scaffold, schema migration, legacy telemetry ingest, and the
8-
> **C2 command channel** (per-device Berry command queue + per-device HOTP auth). OTA-signal piggyback,
9-
> firmware.bin serving, and log reassembly land in later waves.
8+
> **C2 command channel** (per-device Berry command queue + per-device HOTP auth), plus a
9+
> bearer-authenticated **operator control plane** (`cmd/admin`: admin API, encrypted secrets KV, and an
10+
> embedded Svelte operator web UI). OTA-signal piggyback, firmware.bin serving, and log reassembly land
11+
> in later waves.
1012
1113
## Quick start (local / dev)
1214

@@ -51,8 +53,35 @@ GET /<INGEST_TOKEN>/c2?sn=<serial>&ack=<applied_seq>&c=<counter>&otp=<hotp>[&wa
5153
process-wide `LISTEN` connection that fans out in-process to every waiter — or the budget elapses
5254
(→ 204). Absent/`wait<=0` returns 204 immediately (the battery field poll, no connection hold). One
5355
DB connection signals the whole fleet.
54-
- **Enqueue (operator):** insert into `command_queue (serial, script[, note])` — v1 is a SQL/CLI step;
55-
a dedicated admin route lands later.
56+
- **Enqueue (operator):** `POST /api/command` (or per device, `POST /api/devices/{serial}/command`) on
57+
the operator control plane below; the enqueue is attributed to the operator key. A direct SQL insert
58+
into `command_queue (serial, script[, note])` still works for break-glass.
59+
60+
## Operator control plane (`cmd/admin`)
61+
62+
A second binary, built from `Dockerfile.admin` and run as its own compose service — a **process and
63+
address space separate from the public `ingest` parser**, so the privileged write path never sits in the
64+
binary the internet reaches. Bound to host loopback / VPN only (TLS terminates at a tunnel or proxy);
65+
never published.
66+
67+
- **Bearer auth.** Operator keys live in `operator_keys` (sha256 of the token; the plaintext is shown
68+
once at mint and never stored). A soft-revoke (`disabled_at`) authenticates as if absent. Routes split
69+
`auth` (any valid key — reads) vs `requireAdmin` (mutations); `GET /api/whoami` reports
70+
`{key_id, is_admin, label}`. Keys are minted/listed/revoked out-of-band:
71+
`admin create-operator -label <name> [-admin]`.
72+
- **Encrypted secrets KV.** `PUT/GET/DELETE /api/secrets/{name}` over an AES-256-GCM sealed store; the
73+
value is never echoed back. The master key (`SECRETS_KEY`, 32 bytes hex) is injected only into the
74+
admin container, lives in a root-only file outside `.env`, and the service **fails closed** without it.
75+
Break-glass decrypt is an out-of-band subcommand, not an HTTP route. Back up the key with the host —
76+
key loss is total loss.
77+
- **Live events.** `GET /api/events` is a server-sent-events stream (device-roster snapshot + deltas
78+
now; telemetry/log payloads in later waves) with a periodic re-auth that tears the stream down within
79+
~60 s of a key revocation.
80+
- **Operator web UI.** A Svelte 5 SPA embedded via `//go:embed` (one binary, no second container, no
81+
CORS): key login, a live device roster, and read-only degradation for non-admin keys. A checkout
82+
without the bun toolchain still builds — the Go binary serves a 503 hint while every `/api` route stays
83+
functional. Feature pages (OTA, logs, telemetry, Berry, FaaS, Web-USB onboarding) mount into the shell
84+
in later waves. Source + build: `backend/web/` (`bun install && bun run build`).
5685

5786
## Schema migration
5887

0 commit comments

Comments
 (0)