feat: integrate durable authorization audit and runtime composition
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e747-8f27-7242-8df8-8bc44f88c929
This commit is contained in:
parent
3e386147fd
commit
c9b6916dac
14 changed files with 767 additions and 16 deletions
101
docs/owner-access-integration.md
Normal file
101
docs/owner-access-integration.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# HUB-WP-0012 owner integration review — 2026-09-28
|
||||
|
||||
The Hub foundation is committed as `3e38614`. This follow-up delivers an Audit
|
||||
Core sender and runtime composition, and identifies the remaining source
|
||||
contracts. These are owner review inputs, not evidence of deployed grants.
|
||||
|
||||
## Account, root entitlement and tenant facts
|
||||
|
||||
| Owner surface reviewed | Observed behavior | Required integration |
|
||||
| --- | --- | --- |
|
||||
| User Engine `web.py`, `service.py::me` | `/api/v1/me` resolves `(iss, sub)` but creates User/Account/ExternalIdentity records if absent | A side-effect-free authority lookup; Hub must not bootstrap identities to check access |
|
||||
| User Engine `service.py` | `PLATFORM_TENANT = "platform:root"`; `platform-operator` is an actor role | Explicit mapping to IAM `tenant:platform` and the one immutable root principal; a role or string substitution is insufficient |
|
||||
| User Engine tenant administration APIs | Human/edge-oriented routes; no reviewed Hub workload lookup for current root entitlement | Independently authenticated Hub workload, exact lookup scope and current entitlement provenance |
|
||||
| Tenant Engine `/tenants/{tenant_id}` | Current lifecycle and record version, authorized `tenant.read` | Resolve immutable tenant ID versus canonical identifier; preserve owner version and lifecycle |
|
||||
| Tenant Engine `/tenants/{tenant_id}/roles/live` | Live role state with `tenant.role.read.live`, caller supplies an `actor` query | Admit/authenticate the actual Hub workload and its actor assertion; do not mistake query text or a network path for caller authentication |
|
||||
|
||||
The accepted integration must return identity references, account status,
|
||||
explicit current root entitlement, actor/target tenant status, observation times
|
||||
and owner evidence/version references. Unknown identity is denied without
|
||||
creating anything. Revocation must be visible on the next privileged read as
|
||||
well as write; no cached token role supplies current entitlement.
|
||||
|
||||
`LiveFacts` is the Hub-side normalized result, not a wire endpoint invented for
|
||||
an owner. Each source lookup must complete inside its timeout. The observation
|
||||
age is measured from the actual source observation and cannot be reset after
|
||||
slow downstream calls. All joined facts must still be at most five seconds old
|
||||
when policy/audit finish. Missing, ambiguous, inactive or stale facts deny.
|
||||
Producer aliases must come from an explicit owner binding to that identity.
|
||||
|
||||
T01/T02 require owner review of the lookup and root/tenant mapping before a
|
||||
production `FactSource` is configured. The runtime will not load fixture facts,
|
||||
query owner databases directly, forward Hub bearer tokens to other audiences,
|
||||
or use `/me` as an account-provisioning side effect.
|
||||
|
||||
## Audit Core adapter and sender admission
|
||||
|
||||
`AuditCoreSink` implements the actual `docs/event-envelope.md` contract:
|
||||
`POST /v1/events` with eight fields, a distinct rotating sender bearer, and an
|
||||
`Idempotency-Key` matching the event ID. Source is exactly `hub-core`, tenant
|
||||
exactly `tenant:platform`. Only a matching `202 accepted` or `200 duplicate`
|
||||
with a nonempty archive reference counts as custody. Before each append,
|
||||
`/readyz` must report `status=ok`, `durable=true`, and custody class
|
||||
`operational` or its rollout alias `archive`. The entire append is bounded
|
||||
at three seconds, uses TLS, and never follows redirects.
|
||||
|
||||
Allow is blocked until the archive accepts the authorization record. A lost
|
||||
receipt blocks the business operation even if the attempt reached storage. This
|
||||
is a pre-execution authorization journal, not proof that an operation committed.
|
||||
There is no local success buffer or silent redaction. Domain transaction/outcome
|
||||
atomicity and failure detection remain separate T03/T04 acceptance gates.
|
||||
|
||||
The exact verified signed decision is retained under `data.signed_decision` as
|
||||
serialized JSON so another serialization of the archive cannot reorder its Go
|
||||
struct fields. The verifier refuses secret-shaped field names before retention.
|
||||
No end-user bearer, message body or command body is emitted. Independent tests
|
||||
reverify the signed artifact after retrieval from the owner's receiver.
|
||||
|
||||
Proposed receiver registration (no credential values):
|
||||
|
||||
- Name/source: `hub-core`; allowed tenants: only `tenant:platform`.
|
||||
- Write enabled, read disabled; distinct sender tokens with rotation overlap.
|
||||
- `secret_policy=reject`; authorization record classes `hub.access.authorized`,
|
||||
`hub.access.denied`, `hub.access.refused`.
|
||||
- Load-bearing authorization evidence: execution requires receipt. Owner review
|
||||
must settle exact emission-cadence/failure detection; no claim that this journal
|
||||
provides complete domain mutation evidence or archive tamper evidence.
|
||||
|
||||
Credential routing: `warden route show audit-core-senders --json` identifies
|
||||
`ops-mason`, subsystem OpenBao + audit-core, `warden_executes=false`, and currently
|
||||
`resolvable=false`. This route points to registry custody; it does not prove an
|
||||
admitted Hub sender or mint a credential. No secret was requested or retrieved.
|
||||
|
||||
## Runtime assembly
|
||||
|
||||
`SecuritySettings` uses these `HUB_CORE_SECURITY_` environment suffixes:
|
||||
|
||||
| Suffix | Value |
|
||||
| --- | --- |
|
||||
| `ISSUER`, `AUDIENCE`, `ROOT_SUBJECT` | Admitted HTTPS issuer, Hub audience, immutable root subject |
|
||||
| `POLICY_URL`, `POLICY_CALLER` | Dedicated HTTPS PDP and exact admitted ServiceAccount principal |
|
||||
| `POLICY_TOKEN_FILE`, `POLICY_KEYS_FILE` | Absolute projected caller-token and trusted public-key paths |
|
||||
| `AUDIT_URL`, `AUDIT_TOKEN_FILE` | HTTPS receiver and separate absolute sender-token path |
|
||||
|
||||
A host calls `create_app(access_facts=reviewed_owner_adapter)` in enforcement
|
||||
mode. It can alternatively supply an explicit `SecuritySettings` instance.
|
||||
The runtime owns and closes the shared HTTP client; proxy environment variables
|
||||
are not inherited. Partial/invalid composition is rejected. Without an explicit
|
||||
facts adapter, the standalone app stays closed even if security variables exist.
|
||||
No file-backed allowlist or dynamic arbitrary-module loader supplies authority.
|
||||
|
||||
## Evidence boundary
|
||||
|
||||
The opt-in `tests/test_audit_core_owner_contract.py` exercises the actual Audit
|
||||
Core WSGI receiver and durable SQLite storage, including reopen, wrong-credential
|
||||
and lost-receipt cases. A **test-only** readiness fixture reports operational
|
||||
custody to exercise the production client's receipt checks; this is not native
|
||||
operational custody. Unmodified development custody is independently refused.
|
||||
A composed fixture journey verifies a real RSA JWT, fresh facts, an Ed25519
|
||||
policy decision, receiver custody and native Hub write, followed by entitlement
|
||||
withdrawal denial. Real root enrollment/login, service deployment, live key and
|
||||
sender custody, and operational acceptance remain open.
|
||||
Loading…
Add table
Add a link
Reference in a new issue