Implement TEN-WP-0011 security layer conformance
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 37s
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:
parent
80961af91e
commit
672cf4da6e
40 changed files with 2285 additions and 361 deletions
91
tests/test_pip_claims.py
Normal file
91
tests/test_pip_claims.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
"""TEN-WP-0011-T03: PIP claim freshness and live-lookup non-reentry."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
|
||||
import httpx
|
||||
import yaml
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from tenant_engine.app import create_app
|
||||
from tenant_engine.authz import FlexAuthWriteAuthorizer
|
||||
from tenant_engine.domain import CapabilityRole, Tenant, create_role_grant
|
||||
from tenant_engine.flex_auth import FlexAuthCheckClient
|
||||
from tenant_engine.store import InMemoryTenantStore
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_pip_claims_contract_is_published():
|
||||
data = yaml.safe_load((ROOT / "pip-claims.yaml").read_text())
|
||||
assert data["role"] == "pip"
|
||||
classes = data["input_classes"]
|
||||
assert classes["tenant_roles_live"]["cross_request_cache_by_consumer"] is False
|
||||
assert classes["tenant_roles_live"]["request_scoped_memoization"] is True
|
||||
assert data["degradation"]["store_unavailable"]["http_status"] == 503
|
||||
assert data["live_lookup_authorization"]["reenters_tenant_engine"] is False
|
||||
assert data["live_lookup_authorization"]["check_consumes_tenant_roles"] is False
|
||||
|
||||
|
||||
def test_live_lookup_hits_the_store_every_request():
|
||||
store = InMemoryTenantStore()
|
||||
tenant = Tenant.create(tenant_id="t-1", identifier="tenant:friendly:binky")
|
||||
store.create_tenant(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="c-1",
|
||||
granted_at=datetime.now(UTC),
|
||||
)
|
||||
)
|
||||
calls = {"n": 0}
|
||||
original = store.active_roles
|
||||
|
||||
def counting(tenant_id: str):
|
||||
calls["n"] += 1
|
||||
return original(tenant_id)
|
||||
|
||||
store.active_roles = counting # type: ignore[method-assign]
|
||||
from helpers import AllowAllAuthorizer
|
||||
|
||||
client = TestClient(create_app(store=store, authorizer=AllowAllAuthorizer()))
|
||||
assert client.get("/tenants/t-1/roles/live", params={"actor": "flex-auth"}).status_code == 200
|
||||
assert client.get("/tenants/t-1/roles/live", params={"actor": "flex-auth"}).status_code == 200
|
||||
assert calls["n"] == 2
|
||||
|
||||
|
||||
def test_live_lookup_check_does_not_reenter_tenant_engine():
|
||||
"""The authorize call for /roles/live POSTs /v1/check and never GETs us."""
|
||||
seen: list[str] = []
|
||||
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
seen.append(f"{request.method} {request.url.path}")
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"id": "d-live",
|
||||
"effect": "allow",
|
||||
"resource": {},
|
||||
"subject": {},
|
||||
"provenance": {},
|
||||
},
|
||||
)
|
||||
|
||||
store = InMemoryTenantStore()
|
||||
store.create_tenant(Tenant.create(tenant_id="t-1", identifier="tenant:friendly:binky"))
|
||||
client = FlexAuthCheckClient(
|
||||
base_url="https://flex-auth.example.test", transport=httpx.MockTransport(handler)
|
||||
)
|
||||
app = create_app(store=store, authorizer=FlexAuthWriteAuthorizer(client=client))
|
||||
response = TestClient(app).get("/tenants/t-1/roles/live", params={"actor": "flex-auth"})
|
||||
assert response.status_code == 200
|
||||
assert seen == ["POST /v1/check"]
|
||||
assert not any("/roles/live" in item for item in seen)
|
||||
assert not any("/tenants/" in item for item in seen)
|
||||
Loading…
Add table
Add a link
Reference in a new issue