Files
tatlock/tests/core
jpmschweitzerandClaude Fable 5 e8e5d367b6 fix(tenant): guard against sanitization collisions with production tenant
The request-level tenant guard compared the raw user string exactly
(user == PRODUCTION_TENANT), but all local namespaces (Qdrant
collections, Redis keys) are derived through sanitize_user_id(), which
lowercases and strips/maps punctuation. Case or punctuation variants
("JPMSchweitzer", "jpmschweitzer.", " jpmschweitzer") therefore passed
the guard yet resolved to the production namespaces, letting a dev
instance on the shared services read/write production tenant data.

- context.py: compare sanitize_user_id(user) against the sanitized
  production tenant; expose the guard as public apply_tenant_guard()
- config.py: startup refusal validator uses the same sanitized
  comparison, so a colliding DEFAULT_USER refuses startup loudly
  instead of relying on the allowlist fallback
- tests: variant matrix at both config and request-context level,
  plus a non-colliding passthrough case

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 11:23:36 +02:00
..