feat(server): v2 secure-session-core Task 2 - auth rebuild
Some checks failed
Build and Test / Build Server (Linux) (push) Failing after 3m37s
Build and Test / Build Agent (Windows) (push) Successful in 6m37s
Build and Test / Security Audit (push) Successful in 4m10s
Build and Test / Build Summary (push) Has been skipped

SPEC-002 Phase 1 Task 2 (specs/v2-secure-session-core), code-reviewed APPROVED.

- DELETE the JWT-as-agent-key branch in relay validate_agent_api_key (audit
  CRITICAL): agent auth now = per-agent cak_ key (SHA-256 -> connect_agent_keys,
  revoked filtered) OR support code OR deprecated shared AGENT_API_KEY (warned).
  A user JWT can no longer authenticate an agent.
- auth/agent_keys.rs: cak_ gen (OsRng 256-bit) + SHA-256 hash + verify.
- auth/jwt.rs: ViewerClaims + create/validate_viewer_token (5-min TTL,
  purpose=viewer, session_id+tenant_id claims; non-interchangeable with login).
- Admin key issuance: POST/GET/DELETE /api/machines/:agent_id/keys.
- POST /api/sessions/:id/viewer-token mints a session-bound short-lived token.
- Migration 005: organization/site/tags on connect_machines (fixes the silent
  update_machine_metadata write, coord todo faf39fe0).

NOTE: viewer-token minting is gated by AuthenticatedUser only; the AUTHORIZATION
check (admin/permission gate) that closes audit CRITICAL #1 lands in Task 3 (the
viewer WS verification). The viewer WS path (relay/mod.rs:285) is untouched here.
Not cargo-check-verified (no toolchain on the authoring host) - self-reviewed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-29 18:57:12 -07:00
parent fef8111ff3
commit 41691bfb2c
12 changed files with 788 additions and 16 deletions

View File

@@ -0,0 +1,26 @@
-- Migration: 005_machine_metadata.sql
-- Purpose: Add the organization / site / tags columns to connect_machines.
--
-- db::machines::update_machine_metadata (called from relay/mod.rs on every
-- AgentStatus update) has always written `organization`, `site`, and `tags`
-- to connect_machines, but no prior migration ever created those columns.
-- The caller swallows the error (`let _ = ...`), so the write failed silently
-- and the metadata never persisted. This adds the columns so the write
-- succeeds, and the Machine struct now maps them (so SELECT * returns them).
-- Resolves coord todo faf39fe0.
--
-- Idempotent: ADD COLUMN IF NOT EXISTS. Applied on server startup by
-- sqlx::migrate!(); never pre-applied via psql. Ordered after 004.
-- See .claude/standards/gururmm/sqlx-migrations.md.
-- organization / site: nullable free-form text reported by the agent
-- (AgentStatus.organization / AgentStatus.site).
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS organization TEXT;
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS site TEXT;
-- tags: TEXT[] matching the &[String] bound by update_machine_metadata and the
-- repeated-string AgentStatus.tags proto field. NOT NULL DEFAULT '{}' so every
-- row (existing and new) holds an array and decodes cleanly into Vec<String>;
-- the metadata update only overwrites it when the agent reports a non-empty set.
ALTER TABLE connect_machines
ADD COLUMN IF NOT EXISTS tags TEXT[] NOT NULL DEFAULT '{}';