Phase 4: real Tantivy per-tenant isolation (search/src/registry.rs, enterprise/internal/searchclient)
Closes the last named "isolation mechanism" gap: search.proto gains a tenant_id field on SearchRequest; search/src/registry.rs's IndexRegistry resolves it to an on-demand-opened, per-tenant Tantivy index (empty tenant_id keeps today's single default index, so this is purely additive); enterprise/internal/searchclient sets that field from the authenticated request identity in ctx, mirroring chrunner's exact fail-closed "never a parameter" shape. Wired into enterprise-api in place of the shared api/searchclient. Unlike the ClickHouse pieces from the previous two commits, this one is genuinely verified end to end in this environment: Tantivy is an embedded library, not a networked service, so both the Rust index registry (cargo test, cargo clippy --all-targets -- -D warnings, both clean) and the Go client (a real in-process gRPC server) could actually run. registry.rs's tenant_index_is_isolated_from_default_and_other_tenants seeds three real indices with the same term and confirms a tenant-scoped search returns only that tenant's document -- item 3 of the isolation design doc's verification plan, closed for real, not just written. With both ClickHouse and Tantivy isolation now built, the single largest remaining gap is no longer a missing mechanism: it's that nothing forces or flags whether a deployment actually runs enterprise-api instead of plain api, and that ingest itself has no tenant concept for either storage engine (every record still lands in the one shared database/ index no matter what -- undesigned, not just unbuilt). Updated the threat model, architecture doc, CLAUDE.md, and both READMEs accordingly.
This commit is contained in:
@@ -159,15 +159,21 @@ tenant/role from `tenant_memberships`) — genuinely verified, unlike the
|
||||
ClickHouse pieces, via a real fake IdP that signs and verifies actual
|
||||
RS256 tokens (`loginhandler_test.go`, all passing), though never tried
|
||||
against a real external IdP or through a running `enterprise-auth`
|
||||
container. Two things still keep this phase from being done: SAML login
|
||||
(protocol wiring exists, no ACS handler calls it, following OIDC's now
|
||||
-built pattern), and Tantivy/free-text queries have no per-tenant index
|
||||
routing at all (`enterprise-api` closes the ClickHouse half of tenant
|
||||
isolation, not the Tantivy half) — plus a deployment gap worth naming
|
||||
explicitly: nothing yet forces or even flags whether a given deployment
|
||||
is actually running the isolated binary (`enterprise-api`) versus the
|
||||
plain single-tenant one (`api`); both still exist and nothing currently
|
||||
prevents mixing them up. Full accounting:
|
||||
container. Tantivy per-tenant index routing is now built too
|
||||
(`search/src/registry.rs` + `enterprise/internal/searchclient`) —
|
||||
**genuinely verified**, like the OIDC login flow: Tantivy is an embedded
|
||||
library, not a networked service, so the isolation probe (three tenants,
|
||||
same search term, scoped search returns only that tenant's document)
|
||||
actually ran in this environment, no Docker needed. What still keeps
|
||||
this phase from being done: SAML login (protocol wiring exists, no ACS
|
||||
handler calls it, following OIDC's now-built pattern), ingest itself has
|
||||
no tenant concept for either storage engine (every record lands in the
|
||||
one shared ClickHouse database and Tantivy index no matter what —
|
||||
undesigned, not just unbuilt), and a deployment-topology gap that's now
|
||||
the single largest one: nothing yet forces or even flags whether a given
|
||||
deployment is actually running the isolated binary (`enterprise-api`)
|
||||
versus the plain single-tenant one (`api`); both still exist and nothing
|
||||
currently prevents mixing them up. Full accounting:
|
||||
`/docs/security/threat-model.md`; step-by-step verification procedure
|
||||
(not yet run against a live cluster in this environment):
|
||||
`/docs/phase-4-runbook.md`. The rest of this section describes the exit
|
||||
|
||||
Reference in New Issue
Block a user