informed-decision/docs/flex-auth-review-contract.md
tegwick 83849b75d4 Connect policy-gated browser review and audit runtime
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
2026-09-11 00:31:03 +02:00

5.1 KiB

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

{
  "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.