Commit Graph
4 Commits
Author SHA1 Message Date
rootandClaude Opus 5.5 f48e1aac96 fix(security): W4-E1 approvals admin-session only, shared redact table, TMDB key redaction, prod mock gate
- POST /approvals and PATCH /approvals/{id} require a console admin session
  (EndpointDef auth:"session"); API keys incl. admin scope get 403, so an
  organize.execute key can no longer approve its own plan (S1)
- tests for single-use approval checks: expired, revision/payload hash
  mismatch, consumed, revoked, pending/rejected, plan mismatch; re-approve
  after plan change succeeds once and cannot be replayed (S4)
- one redact key table in @umt/contracts shared by server logger and agent
  redactForModel: rsskey, torrent_pass, authkey, downhash, c_secure_pass,
  passkey variants, x-api-key, cookie headers, nested objects/arrays (S2)
- TMDB network errors: message and cause redacted via redactUrl (S3)
- web Agent ?mock=1 only in DEV builds or when pi.provider is fake (S7)
- EndpointDef auth annotations for /auth/*, asserted against
  PUBLIC_AUTH_PATHS (S10); doc drift fixes (S11)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 22:24:44 +08:00
rootandClaude Opus 5.5 6280d52ec3 feat(server): W2-D agent assembly, session API, runAgent/resolveDecision and backend e2e
- Capabilities: all 14 registered (AO: inventory.query, download.plan/submit, organize.plan/execute,
  policy.preview/apply; agent: task.inspect/retry/cancel); startup asserts count == 14.
  Registry injects server-side authorize (automation_grant by action/scope/policy version/budget,
  one-shot approval bound to plan id + payload hash + revision + expiry; model claims ignored;
  automation switch), audit_event, server idempotency keys and a capability_invocation op ledger
  (migration 0021) used for crash reconciliation. download.plan creates draft plans only;
  download.submit promotes draft -> reserved after authorization.
- Agent session API: POST/GET /agent/runs, GET /agent/runs/{id} (events by seq, messages, report),
  POST .../messages (wake), POST .../abort; automation-grants, approvals, capabilities invoke, tasks.
- runAgent task: Pi or fake provider from settings (apiKey via secrets), events persisted to
  agent_run_event then published, resume + ledger reconciliation when pendingOperations > 0,
  waits for goal-linked downloads/imports and reports from business tables (submitted != imported).
- Background triggers: decision.created -> bounded plan_only investigation (dedupe per decision);
  decision.updated(resolved) -> resolveDecision executes chosen option.
- W2 closure: all OpenAPI routes registered in contracts api.ts (+ subset test); TMDB key from
  settings secret_ref with env fallback; PUT /sites/{id}/credentials documented as alias of
  /site-accounts; completion events documented as existing status events.
- e2e (real PG + OpenWorkflow + testkit mocks): RSS->library, agent delegation with grant/deny,
  background continuation, worker kill -9 recovery (single qB add), auto investigation dedupe.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 20:52:12 +08:00
rootandClaude Opus 5.5 ff230e5da7 feat(server): W2-A login gate, secrets, settings, instances, audit, engine panel API and PG-backed SSE bus
- Admin login gate (docs/design/auth-reference.md): admin_user/admin_session/login_attempt
  (migration 0015), one-time setup token logged once + conditional UPDATE, argon2id via
  hash-wasm (WASM; compiled binary has no --allow-ffi), sha256-stored sessions in HttpOnly
  SameSite=Lax cookie umt_session (fixed 12h TTL, soft revoke), HMAC-derived double-submit
  CSRF, IP (5) + account (15) failure limits per 15 min, password change revokes other
  sessions, optional TOTP with replay counter, AuditAction enum.
- Unified auth middleware: cookie session or Bearer API key -> c.var.actor
  {type: admin|api_key, id, name, scopes}; requireScope works for both; requireAdminSession.
- ctx.secrets: AES-256-GCM, per-secret HKDF-SHA256 key from SECRET_MASTER_KEY, AAD bound
  to (id, purpose); ctx.settings: 30s cache invalidated by settings.changed events.
- Endpoints: /auth/*, /settings, /api-keys, /secrets, /audit-events, library-roots,
  downloader/media-server instances (+test), path-mappings (+verify),
  PUT /sites/{id}/credentials, /engine/runs|stats|cancel (read-only openworkflow schema).
- SSE: PgEventBus (sse_event table, migration 0016, LISTEN/NOTIFY umt_events, catch-up by
  seq, pruning, resync); EventBusPort is now async.
- Tests: login/rate limit/revocation/CSRF/TOTP, secrets round trip and no log leakage,
  admin APIs against mock qB/Emby, SSE across two Deno subprocesses.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 19:59:54 +08:00
rootandClaude Opus 5.5 9858b8494d feat(server): ServerModule skeleton with shared ServerContext, worker runs engine + outbox relay (B6)
modules/{auth-settings,sources-identity,acquisition-organize,agent} placeholders listed in
SERVER_MODULES; ServerModule registers routes (under /api/v1, authenticated), tasks,
outbox routes, capabilities and background loops. bootstrap() builds ServerContext (db,
config, logger, events, engine, outbox writer, secrets placeholder, settings reader,
capability registry), fills unregistered tasks with stubs and rejects duplicate task or
outbox ownership. worker starts the OpenWorkflow worker, OutboxRelay and module start().
--role migrate also migrates the engine schema; api/worker connect without migrating.
tasks: TaskRegistry.has, migrateEngineSchema.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 19:30:55 +08:00