2026-09-28 11:44:50 +02:00
|
|
|
|
# Hub access profile 1.0.0 — implementation candidate
|
|
|
|
|
|
|
|
|
|
|
|
HUB-WP-0012 source implementation, 2026-09-28. Owner review and live acceptance
|
|
|
|
|
|
remain open. This profile does not grant platform access or enable public exposure.
|
|
|
|
|
|
|
|
|
|
|
|
## Runtime behavior
|
|
|
|
|
|
|
|
|
|
|
|
`HUB_CORE_ACCESS_MODE=auto` enables enforcement whenever `HUB_CORE_ENV` is not
|
|
|
|
|
|
`development` or `test`. `enforce` also enables it locally. `development` is
|
|
|
|
|
|
rejected in other environments. **Do not deploy this candidate as a routine
|
|
|
|
|
|
upgrade:** the default production factory has no admitted owner adapters yet and
|
|
|
|
|
|
returns 401 for missing credentials and 503 for credential-bearing requests.
|
|
|
|
|
|
The current deployed image and its release configuration have not been changed.
|
|
|
|
|
|
|
2026-09-28 12:17:16 +02:00
|
|
|
|
Without explicit browser composition, only exact `GET /healthz` is public, returning `{"status":"ok"}`. The shared
|
2026-09-28 11:44:50 +02:00
|
|
|
|
ASGI boundary protects docs, readiness, native ports, projections, compatibility
|
|
|
|
|
|
aliases and subsequently attached routes. Unknown method/route/handler combinations,
|
|
|
|
|
|
WebSockets, mounts without admission, and slash redirects without catalog entries
|
|
|
|
|
|
fail closed. Clients must use exact paths. Catalog admission does not override
|
|
|
|
|
|
compatibility feature flags or single-writer/read-only gates. Legacy bearer checks
|
|
|
|
|
|
remain in the development lane; production enforcement never falls back to them.
|
|
|
|
|
|
|
|
|
|
|
|
`hub_core/security/routes.json` is the candidate action catalog. It names each
|
|
|
|
|
|
runtime method, path template and handler, with a stable action per handler/method.
|
|
|
|
|
|
It is packaged in the wheel and tested against actual route construction. Source
|
|
|
|
|
|
inventory generation does **not** auto-admit a new route. Duplicate docs handlers
|
|
|
|
|
|
remain separately inventoried; the boundary selects the first effective route.
|
|
|
|
|
|
These technical action names require flex-auth/owner review before policy delivery.
|
2026-09-28 12:17:16 +02:00
|
|
|
|
Optional browser composition adds four exact `/auth/*` protocol routes and the
|
|
|
|
|
|
`hub.browser.session` action; login initiation is public, callback state is
|
|
|
|
|
|
browser-bound, and session access requires current root authority. See the
|
|
|
|
|
|
[browser integration contract](owner-access-integration.md#browser-composition-source-candidate).
|
2026-09-28 11:44:50 +02:00
|
|
|
|
|
|
|
|
|
|
## Composition and trust
|
|
|
|
|
|
|
|
|
|
|
|
A host composes `create_app(access_controller=AccessController(...))` with:
|
|
|
|
|
|
|
|
|
|
|
|
- `OIDCVerifier`: an explicitly trusted HTTPS issuer and Hub audience, an owned
|
|
|
|
|
|
`httpx.AsyncClient`, RS256 discovery/JWKS, token and assurance lifetime at most
|
|
|
|
|
|
300 seconds, a 60-second key cache, and unknown-key rotation refresh (rate limited
|
|
|
|
|
|
to once per second). Access tokens require `at+jwt` or the KeyCape `typ: Bearer`
|
|
|
|
|
|
payload marker. ID tokens, local issuers/profiles, weak keys, AAL0 and delegated
|
|
|
|
|
|
agents are refused. Strict integer NumericDates and assurance time are required.
|
|
|
|
|
|
- `FactSource.resolve`: an **owner implementation still owed** that queries
|
|
|
|
|
|
authoritative account, root entitlement, actor tenant and target tenant state.
|
|
|
|
|
|
Its result binds issuer, subject, actor tenant, evidence reference and permitted
|
|
|
|
|
|
producer addresses; its age may not exceed five seconds, including after policy
|
|
|
|
|
|
and audit finish. No token role or incoming tenant/identity header supplies facts.
|
|
|
|
|
|
- `FlexPolicy`: a dedicated HTTPS Hub PDP, exact admitted ServiceAccount principal,
|
|
|
|
|
|
a rotating projected caller-token file and an owner-delivered trusted public-key
|
|
|
|
|
|
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.
|
2026-09-28 12:01:42 +02:00
|
|
|
|
- `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;
|
2026-09-28 11:44:50 +02:00
|
|
|
|
a failed sink blocks reads as well as writes. Authorization receipts say
|
|
|
|
|
|
`authorized`, not “operation completed.” Domain commit/outcome audit remains a
|
2026-09-28 14:59:33 +02:00
|
|
|
|
separate concern. Native durable and implemented SQL compatibility mutations have a
|
|
|
|
|
|
[transaction-linked outcome outbox](operation-outcome-audit.md); arbitrary
|
|
|
|
|
|
embedded-host and external mutations remain outside that slice.
|
2026-09-28 11:44:50 +02:00
|
|
|
|
- The root's existing immutable issuer and subject, supplied after owner resolution.
|
|
|
|
|
|
No username, email, first-login promotion or generic role establishes root.
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
2026-09-28 12:01:42 +02:00
|
|
|
|
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
|
2026-09-28 14:32:36 +02:00
|
|
|
|
admission and independent owner probes remain T02–T04 work;
|
|
|
|
|
|
[dependency readiness](access-readiness.md) now reports recent verified operations; see the
|
2026-09-28 12:01:42 +02:00
|
|
|
|
[owner integration review](owner-access-integration.md).
|
2026-09-28 11:44:50 +02:00
|
|
|
|
|
|
|
|
|
|
For this candidate all Hub resources are explicitly **platform-owned**. Other
|
|
|
|
|
|
target tenants are refused. Root requires AAL2/3, active account and tenants,
|
|
|
|
|
|
current root entitlement, and a fresh policy allow for every action. Workloads
|
|
|
|
|
|
receive no root shortcut: a policy grant and current authoritative facts are always
|
|
|
|
|
|
required. Real workload admission remains unproven. Cross-tenant owner administration
|
|
|
|
|
|
and Phase 2 storage/query isolation are not implemented by this classification.
|
|
|
|
|
|
|
|
|
|
|
|
## Policy interoperability and failure handling
|
|
|
|
|
|
|
|
|
|
|
|
The PDP request carries actor, target tenant, action, concrete resource path,
|
|
|
|
|
|
assurance, root entitlement, authoritative evidence reference, and a digest of
|
|
|
|
|
|
HTTP method/path/query/body. Client bodies and bearer tokens are not sent to the
|
2026-09-28 12:17:16 +02:00
|
|
|
|
PDP or audit sink. Body size is bounded at 1 MiB with a ten-second receive deadline. The controller's identity/facts/
|
2026-09-28 11:44:50 +02:00
|
|
|
|
policy/audit chain has a ten-second timeout; individual HTTP calls have three seconds.
|
|
|
|
|
|
A separate refusal-audit attempt is bounded at three seconds.
|
|
|
|
|
|
|
|
|
|
|
|
The verifier requires Ed25519 signing, the submitted request digest, matching
|
|
|
|
|
|
request ID and structured actor/action/resource/tenant/context, enforced caller
|
2026-09-28 15:56:52 +02:00
|
|
|
|
provenance, policy version/digest, a decision age below 30 seconds and a valid
|
|
|
|
|
|
allow lifetime. `Decision.valid_until` is a required finite epoch deadline, derived
|
|
|
|
|
|
from the earliest signed allow expiry, caller expiry and decision-time freshness
|
|
|
|
|
|
limit. The controller checks it before audit and again after durable acceptance,
|
|
|
|
|
|
before returning authority to HTTP, browser or direct SDK callers. Expiry during
|
|
|
|
|
|
custody returns `503 policy_decision_expired`; an authorization receipt is not
|
|
|
|
|
|
permission to execute after expiry. Custom policy adapters must supply this field
|
|
|
|
|
|
from verified provenance, never a fresh deadline invented at receipt time.
|
|
|
|
|
|
It never caches decisions. Every unimplemented obligation and
|
2026-09-28 11:44:50 +02:00
|
|
|
|
non-allow/non-deny effect fails closed; approval requirements cannot be waived.
|
|
|
|
|
|
A malformed/untrusted/unavailable decision returns 503, a verified denial 403,
|
|
|
|
|
|
and invalid authentication 401. Responses are `no-store` and do not expose backend
|
|
|
|
|
|
exceptions. There is no local allow fallback.
|
|
|
|
|
|
|
|
|
|
|
|
Interoperability tests retain flex-auth's real Go-signed fixture, tampered pair,
|
|
|
|
|
|
public test key and original submitted request. Go `encoding/json` emits struct
|
|
|
|
|
|
fields in declaration order and map keys in sorted order. The verifier retains
|
|
|
|
|
|
wire order and HTML escaping for signatures and reproduces the request structs
|
|
|
|
|
|
for `submitted_request_digest`. This is **not** RFC 8785. Duplicate JSON keys and
|
|
|
|
|
|
non-integer decision numbers are outside this candidate profile and fail closed;
|
|
|
|
|
|
a reordered envelope also fails signature verification. Agree broader canonical
|
|
|
|
|
|
encoding with flex-auth before expanding this profile.
|
|
|
|
|
|
|
|
|
|
|
|
## Producers, MCP and embedded hosts
|
|
|
|
|
|
|
|
|
|
|
|
`from_address`, `from_agent` and `author`, when present in a top-level JSON command,
|
|
|
|
|
|
must match the live owner's producer-address set. Native events get a reserved
|
|
|
|
|
|
`payload._hub_access` record containing verified actor/tenant/correlation identity;
|
|
|
|
|
|
client assertions under that key are overwritten. Domain `subject_refs` remain
|
|
|
|
|
|
business data, never proof of origin. Compatibility event implementations and
|
|
|
|
|
|
external publishers still need owner acceptance of equivalent attribution.
|
|
|
|
|
|
|
|
|
|
|
|
Embedded hosts can install `AccessBoundary` and an explicit host route catalog.
|
|
|
|
|
|
Tests prove the common seam on an embedded host; each real host's mounted paths,
|
|
|
|
|
|
features and routers still require inventory and admission. Do not treat the
|
|
|
|
|
|
standalone runtime catalog as admission for every embedded API.
|
|
|
|
|
|
|
|
|
|
|
|
MCP hosts may supply `token_provider`, a callable resolving a **Hub-audience**
|
|
|
|
|
|
credential from the current invocation, with `require_credentials=True`. Credentials
|
|
|
|
|
|
are never retained on the server; requests do not follow redirects when carrying
|
|
|
|
|
|
one. `trailing_slash=False` targets the standalone runtime's native paths. The
|
2026-09-28 12:38:04 +02:00
|
|
|
|
standalone production MCP supports only explicit single-principal stdio credentials;
|
|
|
|
|
|
network transports require an authenticated host composition. The standalone
|
|
|
|
|
|
profile advertises four mapped runtime tools; legacy operations remain embedded-only.
|
2026-09-28 11:44:50 +02:00
|
|
|
|
Many legacy tools target APIs the standalone Hub does not implement. They remain
|
2026-09-28 12:38:04 +02:00
|
|
|
|
unsupported, not silently translated or authorized. Cross-audience delegation
|
|
|
|
|
|
remains open. Browser PKCE sessions/logout are implemented locally; live browser/MCP caller
|
|
|
|
|
|
admission remains open. See the [MCP composition contract](owner-access-integration.md#mcp-caller-composition-and-backend-mapping).
|
2026-09-28 11:44:50 +02:00
|
|
|
|
|
|
|
|
|
|
## Remaining release gates
|
|
|
|
|
|
|
|
|
|
|
|
1. T01: cross-owner contract review, concrete policy vocabulary, effective host and
|
|
|
|
|
|
service-route expansion; the 250-object snapshot is not full route discovery.
|
|
|
|
|
|
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,
|
2026-09-28 12:01:42 +02:00
|
|
|
|
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
|
2026-09-28 11:44:50 +02:00
|
|
|
|
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.
|