Fix: resolve tenants by identifier, not only internal tenant_id

Found via a real cross-service check while implementing key-cape's
KEY-WP-0005-T02: key-cape's Go adapter called GET /tenants/tenant:coulomb/roles
and got a genuine 404 for a tenant that existed. External callers
(key-cape, flex-auth) only ever have a tenant's profile identifier, never
tenant-engine's internal tenant_id (caller-chosen at creation, otherwise
opaque). Every existing test happened to use identical strings for both
fields, so this was invisible until a real, independent second caller
exercised the documented contract.

InMemoryTenantStore gained a _by_identifier index and a _resolve() helper
every method calls first; create_tenant now also rejects a duplicate
identifier under a different internal id (an oversight the same fix
surfaced). 5 new tests, including the exact HTTP-level scenario with colon
characters in the URL path. 65 total, all 60 pre-existing tests unaffected.

Re-verified end-to-end for real: fresh flex-auth + tenant-engine + key-cape's
actual adapter code, over real HTTP -- roles=[IAM] ok=true resolving by
identifier.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-07-24 00:15:26 +02:00
parent 18f510070f
commit 31e237cfa6
4 changed files with 193 additions and 17 deletions

View file

@ -64,6 +64,19 @@ def test_cache_read_roles_returns_active_roles() -> None:
assert response.json() == {"tenant_id": "t-binky", "roles": ["CUS"]}
def test_cache_read_roles_resolves_by_identifier_not_only_internal_id() -> None:
"""The real scenario key-cape's KEY-WP-0005-T02 hits: it only knows the
tenant's profile identifier (the IAM Profile `tenant` claim value), via
a URL path segment containing colons -- never the internal tenant_id.
"""
client = TestClient(create_app(store=_seeded_store()))
response = client.get("/tenants/tenant:friendly:binky/roles")
assert response.status_code == 200
assert response.json() == {"tenant_id": "tenant:friendly:binky", "roles": ["CUS"]}
def test_cache_read_roles_unknown_tenant_is_404() -> None:
client = TestClient(create_app(store=_seeded_store()))
response = client.get("/tenants/does-not-exist/roles")