Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e747-8f27-7242-8df8-8bc44f88c929
101 lines
6.6 KiB
Markdown
101 lines
6.6 KiB
Markdown
# 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.
|