Connect policy-gated browser review and audit runtime

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
tegwick 2026-09-11 00:31:03 +02:00
parent 2cc32168ac
commit 83849b75d4
35 changed files with 2381 additions and 83 deletions

View file

@ -0,0 +1,104 @@
# Flex Auth review consumer contract
Source integration under `INFD-WP-0001-T08`; **production admission pending**.
This is the concrete consumer request for owner review. It does not grant a
role, register a caller or publish an allow policy. The checked Flex Auth source
at `88b354377c8e26b162f1234e673072f1c06dcd89` has no Informed Decision
production package in the examined examples, registry or docs.
## Caller and subject
`POST /v1/check` uses an independently provisioned workload credential, expected
to be a projected Kubernetes service-account token for audience `flex-auth`.
Flex Auth must admit the exact caller/system binding with TokenReview. The
fixture exercises `system:serviceaccount:informed-decision:review` bound to
system `informed-decision`; **that spelling is a proposal until the deployment
and policy owners admit it**. A human `approval-engine` token is never the
caller credential. Wrong service accounts and human-token substitution fail
before evaluation in the actual component test.
The subject comes from the verified KeyCape human session, including verified
roles and unchanged assurance facts. Membership tenant and act scope remain
distinct. The tenant provenance values are the consumer's typed
`directory-asserted` or `registration-supplied`; human provenance is
`authentication-derived`. Unknown routes refuse before a request is made.
The production package must deliberately interpret the admitted transitional
tenant route and action-specific MFA freshness; this surface does not infer a
mandate from membership, the named recipient match or a successful login.
## Closed request profile
```json
{
"id": "fresh-uuid-for-each-check",
"tenant": "tenant:platform",
"subject": {
"id": "VERIFIED-HUMAN-SUBJECT",
"type": "human",
"tenant": "tenant:platform",
"attributes": {
"tenant_source": "registration-supplied",
"principal_type_source": "authentication-derived",
"assurance": {"mfa": {"satisfied": true, "method": "totp", "at": "ISSUER-TIMESTAMP"}},
"roles": ["VERIFIED-ISSUER-ROLE"]
}
},
"action": "read",
"resource": {
"id": "memo:EXACT-MEMO-ID",
"type": "decision-memo",
"system": "informed-decision",
"tenant": "tenant:platform"
},
"context": {
"memo_version": 1,
"approval_id": "EXACT-APPROVAL-ID",
"approval_binding_digest": "CARRIED-NATIVE-SHA256-DIGEST"
},
"policy_version": "OWNER-ADMITTED-VERSION"
}
```
The assurance object above is illustrative; `build_request` carries the verified
issuer object without synthesizing stronger facts. Supported actions are
`read`, `acknowledge`, `accept`, `return`, `discuss`, `decline`. Read covers memo
rendering, original presentation retrieval and packet download. Other verbs
always get their own decision. Only accept can cause an Approval Engine POST.
No `consume`, wildcard action, `view_hash`, presentation id, acknowledgment
state or presentation claim is supplied. This prevents the renderer's evidence
from becoming an input to its own permission decision.
The owner must provide the exact package/version/digest, resource/subject
assignment source, admissible caller, scope and positive/negative fixtures.
The consumer does not guess an operator group or ship a local allow fallback.
The separately pending CCR-2026-0019 reader group does not automatically confer
permission to read or approve a memo.
## Required response and refusal behavior
The response is `flex-auth.decision-record.v1`, with matching request id,
submitted request digest, core actor/resource/action/context binding and exact
package/version/digest pins. The evaluated digest and registry snapshot digest
are observed from the owner; registry enrichment is not repeated locally.
`submitted_digest` implements this consumer's bounded Go JSON request profile,
not a second approval-act canonicalizer. Actual Go checks cover enrichment,
Unicode and HTML escaping; the native approval digest is always carried.
Only an allow with a current TTL and no obligations is supported. Maximum use
is 30 seconds from dispatch, bounded by the returned expiry and not-before;
there is no decision cache. A declared obligation needs explicit implementation
before it can be admitted. Deny, unsupported effects/obligations, stale or
mismatched responses and transport/caller failures all refuse. HTTP 401/403
remains `caller_refused` even when the native caller gate returns plain text.
Each obtained observation is append-only in the private evidence database,
before content exposure or an act. Diagnostic response text and bearer tokens
are not retained. Policy linkage is private content, not part of the emitted
presentation claim. The envelope remains unsigned, so
`decision_attributable=false`; native deployment cannot close `FLEX-WP-0024`.
`tests/fixtures/review-policy/` is deliberately a **fixture-only** package, with
one synthetic human/memo/approval and no production assignment. Its native
package pin proves the consumer seam and cannot be used as admission evidence.
Owner return must include admitted policy/caller pins and deployed allow/refusal
receipts for the exact native human/act before T08 can claim live binding.