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
|
|
@ -47,8 +47,9 @@ A host composes `create_app(access_controller=AccessController(...))` with:
|
|||
set. The token is reread on every call and is separate from the end-user token.
|
||||
Remote `/v1/keys` responses never establish their own trust. Current/previous keys
|
||||
can coexist in the mounted trust file; removing a key takes effect next call.
|
||||
- `Audit.append`: an **owner implementation still owed** that returns only after
|
||||
durable acceptance. Every allow must reach this sink before handler execution;
|
||||
- `AuditCoreSink`: implemented against the owner
|
||||
[eight-field ingestion contract](../../audit-core/docs/event-envelope.md), returning
|
||||
only after an operational-custody probe and explicit durable acceptance. Every allow must reach this sink before handler execution;
|
||||
a failed sink blocks reads as well as writes. Authorization receipts say
|
||||
`authorized`, not “operation completed.” Domain commit/outcome audit remains a
|
||||
separate requirement; this source seam does not claim transactional audit.
|
||||
|
|
@ -58,7 +59,10 @@ A host composes `create_app(access_controller=AccessController(...))` with:
|
|||
Do not implement these missing adapters as a constant allow, in-memory audit sink,
|
||||
or an assertion copied from token claims. Tests use synthetic owners explicitly.
|
||||
The current CLI deliberately provides no fixture adapter or production bypass.
|
||||
A deployment composition factory and dependency health probes remain T02–T04 work.
|
||||
An explicit `SecuritySettings`/owner-facts composition now owns the HTTP client
|
||||
and closes it with the runtime. Audit custody is probed per append. Real owner-facts
|
||||
admission and additional owner dependency probes remain T02–T04 work; see the
|
||||
[owner integration review](owner-access-integration.md).
|
||||
|
||||
For this candidate all Hub resources are explicitly **platform-owned**. Other
|
||||
target tenants are refused. Root requires AAL2/3, active account and tenants,
|
||||
|
|
@ -124,8 +128,8 @@ browser PKCE sessions/logout and real MCP root login remain open.
|
|||
2. T02: immutable root binding, registered audience/redirects, PKCE/MFA/recovery,
|
||||
admitted live facts adapters, attended login/logout and revocation receipts.
|
||||
3. T03: dedicated Hub policy and fact provenance review; authenticated deployment,
|
||||
credential/key custody, durable audit implementation and native rotation probes.
|
||||
4. T04–T05: composed deployable runtime, dependency health probes, all client/extension
|
||||
credential/key custody, real Audit Core sender admission and native rotation probes.
|
||||
4. T04–T05: deploy the admitted composition, complete dependency health probes and all client/extension
|
||||
migrations, domain outcome audit, legacy lane rollback and full root journeys.
|
||||
5. T06–T08: every platform/Railiance receipt, separate public-enable approval and
|
||||
later role/delegation/tenant isolation. No milestone is closed by local fixtures.
|
||||
|
|
|
|||
46
docs/evidence/hub-wp-0012-owner-integration-20260928.md
Normal file
46
docs/evidence/hub-wp-0012-owner-integration-20260928.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# HUB-WP-0012 owner integration continuation — 2026-09-28
|
||||
|
||||
Initial foundation committed and pushed: `3e38614`.
|
||||
|
||||
Implemented in the follow-up:
|
||||
|
||||
- Audit Core sender conforming to its real eight-field ingestion contract,
|
||||
authenticated with a distinct rotating credential, and requiring operational
|
||||
durable custody plus an explicit accepted/duplicate receipt before execution.
|
||||
- Exact verified signed policy artifacts retained in the archive; secret-shaped
|
||||
decision fields fail closed before serialization. Refusals retain verified
|
||||
identity, action and request/resource digests where available.
|
||||
- Explicit `SecuritySettings` + owner `FactSource` runtime composition, bounded
|
||||
HTTP calls, no proxy-environment inheritance, and runtime-owned client cleanup.
|
||||
Configuration alone cannot activate a missing authority implementation.
|
||||
|
||||
Validation:
|
||||
|
||||
- Full suite with `HUB_CORE_AUDIT_CORE_SOURCE=/home/worsch/audit-core`:
|
||||
**304 passed**, one existing TestClient deprecation warning, 52.56 seconds.
|
||||
- Final focused owner/denial checks after enriching refusal attribution: **7 passed**.
|
||||
- Source inventory unchanged and validated: 161 Hub surfaces / 48 platform rows /
|
||||
250 observed cluster objects.
|
||||
- `uv build` succeeds; `git diff --check` passes.
|
||||
|
||||
Five opt-in owner-source cases use the actual Audit Core receiver:
|
||||
|
||||
1. Hub envelope accepted and exact evidence retained across storage reopen.
|
||||
2. Unmodified development custody rejected before posting.
|
||||
3. A lost receipt blocks execution even though the receiver holds the attempt.
|
||||
4. Invalid sender credential creates no record.
|
||||
5. Composed JWT verification, current facts, signed decision, real receiver
|
||||
ingestion and native Hub write; archived decision independently verifies;
|
||||
root entitlement withdrawal denies the next attempt.
|
||||
|
||||
These are local tests with synthetic identities, keys and sender registration.
|
||||
SQLite is durable test storage, not operational production custody. A clearly
|
||||
named test-only readiness fixture simulates that custody classification; no
|
||||
live receiver admission, real root login or platform access is claimed.
|
||||
|
||||
The [owner review](../owner-access-integration.md) records concrete next gates:
|
||||
User Engine's `platform:root` mapping, a non-provisioning immutable identity and
|
||||
root-entitlement lookup (its `/api/v1/me` can create an account), authenticated
|
||||
Tenant Engine caller admission, and actual Hub Audit Core sender custody.
|
||||
`warden route show audit-core-senders --json` routes registry ownership to
|
||||
ops-mason/OpenBao and is unresolved. No secrets were retrieved or grants changed.
|
||||
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