feat: add fail-closed Hub access profile foundation
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / pytest-smoke (push) Failing after 3s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e747-8f27-7242-8df8-8bc44f88c929
This commit is contained in:
tegwick 2026-09-28 11:44:50 +02:00
parent df39fd5f43
commit 3e386147fd
35 changed files with 2009 additions and 195 deletions

View file

@ -25,6 +25,21 @@ def get_contract_validator(request: Request) -> ContractValidator:
return request.app.state.contract_validator
def _attribute_event(body: EventCommand, request: Request) -> EventCommand:
context = getattr(request.state, "hub_access", None)
if context is None:
return body
# Reserved server provenance overrides any payload assertion. Domain
# subject_refs remain business data and are never authentication evidence.
return body.model_copy(update={"payload": {**body.payload, "_hub_access": {
"issuer": context.actor.issuer, "subject": context.actor.subject,
"principal_type": context.actor.principal_type,
"actor_tenant": context.actor.tenant,
"target_tenant": context.facts.target_tenant,
"correlation_id": context.correlation_id,
}}})
def create_ports_router() -> APIRouter:
router = APIRouter(prefix="/ports")
@ -112,6 +127,7 @@ def create_ports_router() -> APIRouter:
)
async def append_progress(
body: EventCommand,
request: Request,
store: PortStore = Depends(get_port_store),
validator: ContractValidator = Depends(get_contract_validator),
) -> PortAccepted:
@ -119,7 +135,7 @@ def create_ports_router() -> APIRouter:
validator.validate_event_family(body.event_type, "progress")
except ValueError as exc:
raise HTTPException(status_code=422, detail=str(exc)) from exc
return await store.append_progress(body)
return await store.append_progress(_attribute_event(body, request))
@router.post(
"/events/interaction",
@ -130,6 +146,7 @@ def create_ports_router() -> APIRouter:
)
async def append_interaction(
body: EventCommand,
request: Request,
store: PortStore = Depends(get_port_store),
validator: ContractValidator = Depends(get_contract_validator),
) -> PortAccepted:
@ -137,7 +154,7 @@ def create_ports_router() -> APIRouter:
validator.validate_event_family(body.event_type, "interaction")
except ValueError as exc:
raise HTTPException(status_code=422, detail=str(exc)) from exc
return await store.append_interaction(body)
return await store.append_interaction(_attribute_event(body, request))
@router.get(
"/projections/{projection_id}",