docs(app): document users HTTP admin model, bump 0.10.0
Add a gotcha describing the unified-storage model (the server writes users to the same store/KV as rooms), the admin-only HTTP surface, and the CLI-seeds-admin-#0 bootstrap. Bump the version 0.9.0 -> 0.10.0 and add the capability growth log entry for the new HTTP admin users API. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
name: unibus
|
||||
lang: go
|
||||
domain: infra
|
||||
version: 0.9.0
|
||||
version: 0.10.0
|
||||
description: "Bus de mensajería unificado sobre NATS+JetStream con cifrado E2E por room (megolm/olm reducido): service de membresía/claves, librería cliente y peers demo."
|
||||
tags: [service, messaging, nats, e2e]
|
||||
uses_functions:
|
||||
@@ -122,6 +122,21 @@ Para apuntar a un NATS externo en producción: `--nats-url nats://host:4222` en
|
||||
las rutas GET de lectura. Confía en la red interna. Las rutas mutantes
|
||||
(`/rooms`, `/invite`, `/rekey`) sí exigen firma Ed25519 del owner sobre los
|
||||
bytes canónicos de la request. Endurecer es fase posterior.
|
||||
- **Gestión de usuarios: storage unificado, alta por dos vías.** El allowlist de
|
||||
usuarios vive en el MISMO store que las rooms (`pkg/membership.Store`): SQLite en
|
||||
single-node, JetStream KV replicado (`UNIBUS_users`) en cluster. El `Server` ya
|
||||
tiene ese store privilegiado abierto (es quien sirve el KV en cada nodo), así que
|
||||
expone `GET/POST /users` y `POST /users/{signpub}/revoke` como API HTTP admin-only,
|
||||
simétrica con las rutas de rooms: el panel de administración firma como admin y el
|
||||
server ejecuta la mutación contra el mismo store. El panel NO necesita `--db`, ni la
|
||||
identidad interna, ni correr en un nodo del cluster; funciona idéntico en single-node
|
||||
y cluster. La autorización es default-deny: solo un firmante que el store confirma como
|
||||
`role == "admin"` activo pasa, cualquier otro recibe 403 (encima de la firma+nonce+TLS
|
||||
ya existentes). La CLI `membershipd user add --store kv` sigue existiendo SOLO para
|
||||
sembrar el admin #0 (bootstrap del huevo-gallina: sin un admin sembrado no hay quién
|
||||
firme el primer `POST /users`); a partir de ahí toda la gestión es HTTP admin-only. El
|
||||
alta es idempotente igual que la CLI: re-alta de una clave ya registrada = 409, sin
|
||||
sobrescribir ni elevar rol; el revoke es un flip de status (sin hard-delete), auditable.
|
||||
- **Identidad = secreto crítico.** El archivo de identidad (`worker.id`,
|
||||
`chat.id`) contiene las claves privadas (Ed25519 + X25519). Se escribe 0600.
|
||||
Perderlo = mensajes ilegibles, sin recuperación. Trátalo como una clave SSH.
|
||||
@@ -154,6 +169,28 @@ agent.<nombre>.{in,out} inbox/outbox de agente LLM (agent.scout.in)
|
||||
|
||||
## Capability growth log
|
||||
|
||||
- v0.10.0 (2026-06-07) — API HTTP admin-only de gestión de usuarios, cerrando la
|
||||
última asimetría del control plane: las rooms tenían superficie HTTP firmada
|
||||
(`POST /rooms`, etc.) pero los users solo se gestionaban por CLI local o acceso
|
||||
directo al store. Se añaden `GET /users` (lista completa, incluidos revocados),
|
||||
`POST /users` (alta `{sign_pub, handle, role}`: valida hex de 64 chars + role en
|
||||
`{admin, member}`, 409 idempotente que no sobrescribe ni eleva rol) y
|
||||
`POST /users/{signpub}/revoke` (flip de status, sin hard-delete). Los tres pasan por
|
||||
un helper `requireAdmin` default-deny que confirma contra el store que el firmante
|
||||
autenticado es un user `role == "admin"` activo (el endpoint id es un hash one-way de
|
||||
la clave, así que el contexto lleva ahora también el `sign_pub` hex del firmante para
|
||||
resolver `GetUser`); cualquier otro firmante recibe 403, encima de la firma+nonce+TLS+
|
||||
enforce ya heredadas del middleware. NO se abre conexión KV nueva ni se usa la identidad
|
||||
interna: el server escribe vía su `s.store` privilegiado, el MISMO que las rooms (SQLite
|
||||
single-node, KV `UNIBUS_users` en cluster). `pkg/client` gana `ListUsers/AddUser/RevokeUser`
|
||||
(tipo plano `UserInfo`) firmando como admin, así la pestaña Users del panel deja de
|
||||
necesitar `--db`/acceso KV directo. La CLI `membershipd user add --store kv` queda SOLO
|
||||
para sembrar el admin #0 (bootstrap). La validación de `sign_pub` se unifica en
|
||||
`membership.ValidateSignPubHex`, reusada por la CLI y los handlers. Tests nuevos:
|
||||
no-admin → 403 en los tres endpoints, roundtrip admin add→list→revoke, y validación
|
||||
(hex inválido → 400, role inválido → 400, re-alta → 409), más un test de cliente contra
|
||||
un membershipd embebido. Cambios 100% aditivos: el comportamiento single-node y de las
|
||||
rutas de rooms no cambia; vet/build/test verdes.
|
||||
- v0.9.0 (2026-06-07) — cierre de los gaps que el despliegue del cluster (report
|
||||
0011) dejó abiertos (report 0012). (GAP A) Nueva capability `membershipd user
|
||||
add|list|revoke --store kv`: alta/baja de usuarios contra el KV replicado del
|
||||
|
||||
Reference in New Issue
Block a user