tenant-engine/tests/test_store.py
tegwick 672cf4da6e
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 37s
Implement TEN-WP-0011 security layer conformance
Engine/PIP declaration is now checkable (layer.yaml plus a Tooling-client
scan). Writes persist a decision record or the published fail-closed
stance, live-lookup freshness is published, events_for is tenant-scoped,
and mutation evidence drains to audit-core from a local outbox without
blocking the mutation.

Sender registration is requested as AUDIT-IN-0002. Boundary-contract
amendment is requested as NET-IN-0002.

Assistant: grok
Assistant-Session: 01a04cea-e5e8-7081-a0fc-808ebbc35fa9
2026-08-29 13:02:51 +02:00

198 lines
6.2 KiB
Python

from datetime import UTC, datetime
import pytest
from tenant_engine.domain import CapabilityRole, PlanAssignment, Tenant, create_role_grant
from tenant_engine.store import (
GrantNotFoundError,
InMemoryTenantStore,
TenantAlreadyExistsError,
TenantNotFoundError,
)
def _store_with_tenant(
*, grouping: str = "friendly", name: str = "binky"
) -> tuple[InMemoryTenantStore, Tenant]:
store = InMemoryTenantStore()
tenant = Tenant.create(tenant_id=f"t-{name}", identifier=f"tenant:{grouping}:{name}")
store.create_tenant(tenant)
return store, tenant
def test_create_and_get_tenant() -> None:
store, tenant = _store_with_tenant()
assert store.get_tenant(tenant.tenant_id) == tenant
def test_create_duplicate_tenant_raises() -> None:
store, tenant = _store_with_tenant()
with pytest.raises(TenantAlreadyExistsError):
store.create_tenant(tenant)
def test_get_unknown_tenant_raises() -> None:
store = InMemoryTenantStore()
with pytest.raises(TenantNotFoundError):
store.get_tenant("does-not-exist")
def test_grant_and_active_roles() -> None:
store, tenant = _store_with_tenant()
grant = create_role_grant(
tenant=tenant,
grant_id="g-1",
role=CapabilityRole.CUS,
grant_reason="manual_grant",
plan_id=None,
granted_by="ops",
correlation_id="corr-1",
granted_at=datetime.now(UTC),
)
store.grant_role(grant)
assert store.active_roles(tenant.tenant_id) == frozenset({CapabilityRole.CUS})
def test_revoke_removes_role_from_active_set_but_keeps_record() -> None:
store, tenant = _store_with_tenant()
grant = create_role_grant(
tenant=tenant,
grant_id="g-1",
role=CapabilityRole.VEN,
grant_reason="manual_grant",
plan_id=None,
granted_by="ops",
correlation_id="corr-1",
granted_at=datetime.now(UTC),
)
store.grant_role(grant)
revoked = store.revoke_role(tenant_id=tenant.tenant_id, grant_id="g-1", at=datetime.now(UTC))
assert revoked.revoked_at is not None
assert store.active_roles(tenant.tenant_id) == frozenset()
def test_revoke_unknown_grant_raises() -> None:
store, tenant = _store_with_tenant()
with pytest.raises(GrantNotFoundError):
store.revoke_role(tenant_id=tenant.tenant_id, grant_id="missing", at=datetime.now(UTC))
def test_non_exclusive_roles_coexist() -> None:
store, tenant = _store_with_tenant()
for role in (CapabilityRole.CUS, CapabilityRole.VEN):
store.grant_role(
create_role_grant(
tenant=tenant,
grant_id=f"g-{role.value}",
role=role,
grant_reason="manual_grant",
plan_id=None,
granted_by="ops",
correlation_id="corr-1",
granted_at=datetime.now(UTC),
)
)
assert store.active_roles(tenant.tenant_id) == frozenset(
{CapabilityRole.CUS, CapabilityRole.VEN}
)
def test_assign_plan() -> None:
store, tenant = _store_with_tenant()
store.assign_plan(
PlanAssignment(tenant_id=tenant.tenant_id, plan_id="plan-x", assigned_at=datetime.now(UTC))
)
events = store.events_for(tenant.tenant_id)
assert any(
event.event_type == "plan_assigned" and event.payload["plan_id"] == "plan-x"
for event in events
)
def test_get_tenant_resolves_by_identifier_not_only_internal_id() -> None:
"""Found via a real cross-service check (KEY-WP-0005-T02 against a live
tenant-engine): external callers like key-cape and flex-auth only ever
have the tenant's profile identifier (the IAM Profile `tenant` claim
value), never its internal tenant_id, which is caller-chosen at
creation and otherwise opaque.
"""
store, tenant = _store_with_tenant()
by_internal_id = store.get_tenant(tenant.tenant_id)
by_identifier = store.get_tenant(tenant.identifier)
assert by_internal_id == by_identifier == tenant
def test_active_roles_resolves_by_identifier() -> None:
store, tenant = _store_with_tenant()
store.grant_role(
create_role_grant(
tenant=tenant,
grant_id="g-1",
role=CapabilityRole.CUS,
grant_reason="manual_grant",
plan_id=None,
granted_by="ops",
correlation_id="corr-1",
granted_at=datetime.now(UTC),
)
)
assert store.active_roles(tenant.identifier) == frozenset({CapabilityRole.CUS})
def test_revoke_role_resolves_by_identifier() -> None:
store, tenant = _store_with_tenant()
store.grant_role(
create_role_grant(
tenant=tenant,
grant_id="g-1",
role=CapabilityRole.CUS,
grant_reason="manual_grant",
plan_id=None,
granted_by="ops",
correlation_id="corr-1",
granted_at=datetime.now(UTC),
)
)
revoked = store.revoke_role(tenant_id=tenant.identifier, grant_id="g-1", at=datetime.now(UTC))
assert revoked.revoked_at is not None
assert store.active_roles(tenant.tenant_id) == frozenset()
def test_create_tenant_rejects_duplicate_identifier_with_different_internal_id() -> None:
store, tenant = _store_with_tenant()
other = Tenant.create(tenant_id="a-different-internal-id", identifier=tenant.identifier)
with pytest.raises(TenantAlreadyExistsError):
store.create_tenant(other)
def test_every_mutation_emits_an_event() -> None:
store, tenant = _store_with_tenant()
grant = create_role_grant(
tenant=tenant,
grant_id="g-1",
role=CapabilityRole.CUS,
grant_reason="manual_grant",
plan_id=None,
granted_by="ops",
correlation_id="corr-1",
granted_at=datetime.now(UTC),
)
store.grant_role(grant)
store.revoke_role(tenant_id=tenant.tenant_id, grant_id="g-1", at=datetime.now(UTC))
store.assign_plan(
PlanAssignment(tenant_id=tenant.tenant_id, plan_id="plan-x", assigned_at=datetime.now(UTC))
)
event_types = [event.event_type for event in store.events_for(tenant.tenant_id)]
assert event_types == ["tenant_created", "role_granted", "role_revoked", "plan_assigned"]