Implement TEN-WP-0011 security layer conformance
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 37s

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
This commit is contained in:
tegwick 2026-08-29 13:02:51 +02:00
parent 80961af91e
commit 672cf4da6e
40 changed files with 2285 additions and 361 deletions

View file

@ -1,20 +1,15 @@
from datetime import UTC, datetime
from fastapi.testclient import TestClient
from helpers import AllowAllAuthorizer
from tenant_engine.app import create_app
from tenant_engine.authz import WriteAuthorizer
from tenant_engine.domain import CapabilityRole, Tenant, create_role_grant
from tenant_engine.store import InMemoryTenantStore, TenantStore
class _AllowAll(WriteAuthorizer):
def authorize(self, *, action: str, tenant_id: str, actor: str) -> None:
return None
def _client(store: TenantStore) -> TestClient:
return TestClient(create_app(store=store, authorizer=_AllowAll()))
return TestClient(create_app(store=store, authorizer=AllowAllAuthorizer()))
class _BrokenStore:
@ -43,8 +38,11 @@ class _BrokenStore:
def assign_plan(self, assignment):
return self._delegate.assign_plan(assignment)
def events(self):
return self._delegate.events()
def events_for(self, tenant_id):
return self._delegate.events_for(tenant_id)
def record_authorization(self, record):
return None
def _seeded_store() -> InMemoryTenantStore:
@ -81,9 +79,7 @@ def test_cache_read_roles_resolves_by_identifier_not_only_internal_id() -> None:
a URL path segment containing colons -- never the internal tenant_id.
"""
client = _client(_seeded_store())
response = client.get(
"/tenants/tenant:friendly:binky/roles", params={"actor": "key-cape"}
)
response = client.get("/tenants/tenant:friendly:binky/roles", params={"actor": "key-cape"})
assert response.status_code == 200
assert response.json() == {"tenant_id": "tenant:friendly:binky", "roles": ["CUS"]}