Skip to content

Build TicVision's authenticated API on Bonfire DB - #43

Open
aanishs wants to merge 2 commits into
mainfrom
codex/ticvision-core-vertical-0714
Open

Build TicVision's authenticated API on Bonfire DB#43
aanishs wants to merge 2 commits into
mainfrom
codex/ticvision-core-vertical-0714

Conversation

@aanishs

@aanishs aanishs commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • expose authenticated, Practice-scoped POST /search and POST /context from the
    production Bonfire API
  • compose the existing governed proposal/approve/commit surface through the same
    membership-derived authentication boundary
  • add fail-closed OIDC configuration, collision-safe actor identities, audited membership
    lookup faults, and separate liveness/readiness probes
  • align the repository README and production-image CI smoke with TicVision being built on
    Bonfire DB; the dogfood remains a reference POC

Issue alignment

Closes #16.

Refs #36 and #37. This PR is a vertical slice of #37; it does not close #37 while the
Patient/Consent work in #19 and the remaining acceptance surface are outstanding.

Production admission limits and database execution deadlines are tracked separately in
#42.

Verification

  • full Turbo test graph: 10/10 tasks passed
  • focused API/auth/readiness integration battery: 51/51 passed
  • API package after test-harness structural cleanup: 37/37 passed
  • Stage-2 execution evaluations: 35/35 passed
  • full build: 7/7 packages
  • Biome, TypeScript, ESLint, ast-grep, dependency-cruiser, Knip, jscpd, comment hazards,
    and synthetic-data scan passed
  • rebuilt the pinned Bun 1.3.14 production image: /health and /ready returned 200;
    /search, /context, and /governance/proposals returned typed 401 responses without
    a Bearer token

All fixtures and credentials used during verification were synthetic/local-only.

@aanishs

aanishs commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

Second-pass review (independent of authorship; sampled the trust-boundary hunks + full CI):

Merge-ready. What I checked:

  • auth-hook: membership-lookup failure now distinct from no-membership (500 AUTH_MEMBERSHIP_LOOKUP_FAILED, audited, vs 403) — correct fail-closed semantics; collision-safe authActorId threaded into handler context.
  • oidc-config: HTTPS-only endpoints, issuer rejects query/fragment, clock tolerance capped at 300s — fails closed on config, not open.
  • MCP tool schemas now import MAX_SEARCH_QUERY_LENGTH/MAX_SEARCH_TOP_N from core — kills a bounds-drift class.
  • Integration battery enters through buildApp (production composition: JWT → membership → RLS → search → CCP → envelope), not mocked seams.
  • All 8 checks green (build/test/semgrep/gitleaks/jscpd/knip/boundaries/format).

Note: this PR is also the gating dependency for the access-pattern eval's arm 4 (graph-assisted planning via /context) — the equalizer prediction is on record in #39. Merging unblocks that experiment same-day.

@aanishs

aanishs commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Adversarial audit (codex, high effort — exploratory pass over all open items; treat as input, not verdicts):

  1. /health is not a liveness probe: it queries Postgres and pgvector. A database outage therefore marks the process dead and can trigger restart storms, directly contradicting the claimed liveness/readiness separation. Liveness should test only process/event-loop health.

  2. /ready checks only nine relation names. It can return 200 with incompatible columns, missing functions/indexes/RLS policies, stale migrations/projections, or unusable synthetic OIDC configuration. The image smoke likewise proves only unauthenticated 401s—not successful OIDC, membership binding, or tenant isolation.

  3. Authorization denial has unsafe API semantics: /search returns 200 with an empty result set while /context returns 403. Agent clients can easily interpret “not authorized” as “no clinical evidence exists,” creating a dangerous false-negative. Denial should be unmistakable at the HTTP/envelope boundary.

  4. Expensive authenticated search/context are exposed while admission control, concurrency limits, and SQL deadlines are explicitly deferred to Bound public API admission and database execution time #42. Query-length and topN limits do not bound vector/FTS work. Worse, every authentication failure appends to one SYSTEM hash chain, creating a globally serialized, unauthenticated write hotspot that can amplify token-flood DoS into DB contention and audit-table growth.
    (Revises my earlier merge-ready note: findings 1 and 3 — liveness probe querying the DB, and 200-empty vs 403 denial semantics — look like cheap pre-merge fixes worth taking; 2 and 4 are reasonable fast-follows alongside Bound public API admission and database execution time #42.)

@aanishs

aanishs commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Delegated merge gate (codex sol/xhigh, final-review prompt): VERDICT: REQUEST_CHANGES — so per our gate rule I'm not approving yet. Its one merge-blocker (rest are fast-follows):

The authorization semantic mismatch is a merge-blocker. /search deliberately converts policy denial into 200 plus an empty result set, while /context correctly returns 403. That can produce a clinically meaningful false negative and would establish unsafe behavior for the downstream experiment to integrate against. The fix is small: return a stable 403 denial envelope from both routes and update tests.

The other findings are legitimate fast-follows at this stage. /health is mislabeled and should become process-only; /ready should eventually verify migration compatibility and critical RLS/functions, but DB-backed integration tests provide reasonable pre-production coverage. Admission controls and SQL deadlines may remain in #42 for a gated experiment, provided they land before untrusted deployment. The unauthenticated SYSTEM-chain write hotspot should be explicitly added to that requirement because it enables amplification without valid credentials.

One small fix (uniform 403 denial envelope on /search + /context + tests) flips this to approve.

@aanishs
aanishs marked this pull request as ready for review July 24, 2026 01:25
@aanishs
aanishs requested a review from AJ112103 July 24, 2026 01:26
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.

[P0] Wire an authenticated Bonfire API vertical slice [decision] One engine or two — whose spec governs? (two-builds reconciliation)

1 participant