Implement authenticated custody observations and durable root-grant baseline
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 27s
Account journey acceptance / journeys (push) Failing after 6s

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a1029d-2c93-7500-a0e0-e3e089668b29
This commit is contained in:
tegwick 2026-10-03 19:50:15 +02:00
parent 1999a144c9
commit 0d0751d39d
18 changed files with 1129 additions and 14 deletions

View file

@ -9,6 +9,8 @@ from dataclasses import dataclass, field, replace
from datetime import datetime, timedelta
from typing import Any, Callable, Iterable, Mapping
from user_engine.custody import CustodyObservationAdapter
from user_engine.domain import (
Account,
AccessControlFact,
@ -110,7 +112,7 @@ class ReadinessReport:
@dataclass(frozen=True)
class AccountAuthority:
"""Current account state only; not a root entitlement or tenant lifecycle grant."""
"""Account state and optional observed custody fact; never authorization."""
issuer: str
subject: str
tenant: str
@ -121,6 +123,7 @@ class AccountAuthority:
tenant_account_status: AccountStatus | None
observed_at: datetime
decision_id: str | None
root_grant: Mapping[str, Any] | None = None
@dataclass(frozen=True)
@ -310,11 +313,13 @@ class UserEngineService:
identity_adapter: IdentityClaimsAdapter,
authorization: AuthorizationCheckPort,
factor_verifier: FactorVerificationAdapter | None = None,
custody: CustodyObservationAdapter | None = None,
) -> None:
self.store = store
self.identity_adapter = identity_adapter
self.authorization = authorization
self.factor_verifier = factor_verifier
self.custody = custody
if not self.store.ready:
self.store.migrate()
@ -1820,6 +1825,8 @@ class UserEngineService:
account_status=account.status,
tenant_account_status=scoped.status if scoped is not None else None,
observed_at=observed_at, decision_id=decision.decision_id,
root_grant=(self.custody.observe(issuer=issuer, subject=subject, tenant=tenant)
if self.custody is not None else None),
)
def create_user(