Skip to content

fix(cli): wire bearer token, audit store, and attestation staleness into the live server - #278

Merged
imran-siddique merged 2 commits into
fix/audit-chain-sqlite-persistencefrom
fix/wire-startup-context
Jun 11, 2026
Merged

fix(cli): wire bearer token, audit store, and attestation staleness into the live server#278
imran-siddique merged 2 commits into
fix/audit-chain-sqlite-persistencefrom
fix/wire-startup-context

Conversation

@imran-siddique

Copy link
Copy Markdown
Member

Summary

Security review found that cli.start() (the only production entrypoint) never wired the components run_startup() validates:

  • AUTH-001 (critical): the validated bearer token was never passed to MCPServer, so the auth middleware was never installed -- every protected endpoint (/mcp, /audit/export, break-glass /catalog/exception, session reset) was reachable unauthenticated in production. Unit tests passed because they construct MCPServer(bearer_token=...) directly.
  • AUDIT-001: AuditChain was constructed directly instead of via SessionManager.create_session(), so the SQLite store added in fix(audit): persist audit chain to SQLite WAL store on every append (AUDIT-001) #276 was opened at startup and then never written -- persistence was inert in the live path.
  • AUDIT-002: the chain was never TEE-anchored in the live path.
  • Staleness fail-open: CMCPProxy never received attestation_generated_at, so _check_health() could never mark attestation stale.

Changes

  • Extract composition into cli.build_server(ctx); start calls it. All validated context components are now threaded through.
  • Add threading.Lock around the shared SQLite connection in SqliteAuditStore (single connection, check_same_thread=False, used from async handlers and worker threads).
  • New tests/unit/test_cli_wiring.py: 5 regression tests against the real entrypoint composition, including a TestClient 401/200 check, SQLite persistence check, TEE anchor check, and attestation timestamp check.

Stacked on #276 (requires RuntimeContext.audit_store).

Test plan

  • pytest tests/ -- 650 passed, 1 skipped (pre-existing)
  • New wiring tests fail when run against the previous cli.py body

Generated with Claude Code

… timestamps into the live server

run_startup() validated the bearer token, opened the SQLite audit store, and
produced attestation timestamps, but cli.start() dropped all of them:

- MCPServer was built without bearer_token, so every protected endpoint
  (/mcp, /audit/export, /catalog/exception, /sessions/*) was reachable
  unauthenticated in production (AUTH-001 dead in the live path).
- AuditChain was built directly instead of via SessionManager, so entries
  never reached the SQLite store (AUDIT-001 inert) and the chain was never
  TEE-anchored (AUDIT-002).
- CMCPProxy never received attestation_generated_at, so the staleness
  check could not fire (fail-open).

Extract the composition into cli.build_server(ctx) and add regression tests
that exercise the real entrypoint wiring, including a TestClient 401 check.

Also serialise SqliteAuditStore access with a threading.Lock: the single
connection is shared across async handlers and worker threads with
check_same_thread=False.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant