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

@ -1,7 +1,8 @@
# Browser authentication and Approval Engine transport
Implemented under `INFD-WP-0001-T08`. The service currently supplies sign-in and
sign-out. It does not yet render memos or expose an approval-entry route.
Implemented under `INFD-WP-0001-T08`. The service supplies sign-in and sign-out;
explicit owner configuration enables the protected memo and human-response
routes described in [protected-browser-review.md](protected-browser-review.md).
Install and exercise from the repository:
@ -25,8 +26,9 @@ The entrypoint listens on `127.0.0.1:8080` for a local reverse proxy. The public
origin/callback is fixed at `https://decisions.coulomb.social/auth/callback`;
Host, forwarded headers and return URLs cannot replace it. A development HTTP
listener does not replace this HTTPS callback registration. Deployment and
registration remain pending. `/healthz` checks this process; `/readyz` returns
503 because the protected approval path is incomplete.
registration rollout remain pending. `/healthz` checks this process; `/readyz`
returns 503 without owner review configuration and recent audit delivery health.
Readiness is not a declaration of native policy/login/custody admission.
## Identity boundary
@ -84,7 +86,7 @@ POST bodies are empty objects: Approval Engine derives identity and evidence
from its verified token and discards caller content. The adapter extracts
`(approval_id, subject_id, approved_at)` from the matching actual human entry,
never `updated_at` or local time. A `409 duplicate_approver` triggers a GET of
that original entry and returns `duplicate=True`. The eventual UI must preserve
that original entry and returns `duplicate=True`. The controller preserves
the original presentation correlation; it cannot attach a new presentation to
an old entry just because a duplicate exists. Other conflicts remain refusals.
@ -93,17 +95,12 @@ There is no automatic POST retry. Durable disposition processing must reconcile
the current engine entry and its correlation before reporting success or
offering a retry. A failed dependency must never be recorded as a human decline.
The client is an internal seam, not a sufficient binding flow. Before a browser
route can call it, T08 must connect:
The client is an internal seam. `review.py` now connects fresh PDP entitlement,
durable presentations, actor/version/acknowledgment guards, local responses,
the transactional outbox and the original-entry recovery rules. `runtime.py`
schedules bounded delivery and reconciliation. No consume route exists.
1. The access-engine entitlement decision before rendering a named memo.
2. Wire the durable presentation/version, actor match and required acknowledgments.
3. Wire persisted dispositions and the transactional outbox, including return/discuss.
4. Independent audit custody/delivery and entry-correlation reconciliation.
5. Native registered KeyCape login and the deployed Approval Engine proof.
The browser currently exposes no memo or entry route and no consume capability.
The legacy `evidence.Outbox` is an in-memory test double. `Store` now supplies
durable atomic state/evidence, and `audit.py` supplies delivery to the real
receiver contract; see [durable-review-evidence.md](durable-review-evidence.md).
Native custody, policy/controller integration and live admission stay in T08.
The legacy `evidence.Outbox` is an in-memory test double; `Store` supplies
durable atomic state/evidence. See [durable-review-evidence.md](durable-review-evidence.md).
Native policy/caller assignment, registered human login, deployment and
independent custody remain in T08. Disposable browser success does not close them.

View file

@ -1,9 +1,10 @@
# Durable review evidence and audit delivery
Implemented under `INFD-WP-0001-T08`. `store.py` replaces the domain tests'
in-memory outbox with a persistent internal store. It does not expose a browser
route, decide entitlement, or authorize an approval entry. `web.py` still has
no memo/entry routes and `/readyz` remains 503.
in-memory outbox with a persistent internal store. `review.py` and `web.py` now
connect it to the protected browser flow; the store itself never decides
entitlement. See [protected-browser-review.md](protected-browser-review.md)
for configuration, policy observations, schema v2 migration and readiness.
## Storage and recovery
@ -56,7 +57,7 @@ These are internal delivery records, not cached approval validity:
1. Record the human's accept intent and its evidence before an engine POST.
2. The controller must obtain a fresh applicable access-engine decision, verify
the session and compare the memo's carried digest with the live approval.
**That controller/policy integration is still pending.**
`review.py` supplies these checks and persists the exact observation before use.
3. `begin_submission` atomically reserves one attempt. A stale presentation
cannot start; a memo cannot be revised while its entry attempt is in flight
or unresolved. Network I/O happens outside the SQLite transaction.
@ -76,7 +77,8 @@ does not prove which presentation caused it. The store does not attach it to
the latest view or automatically POST again. A crash after reservation likewise
does not reopen dispatch. The records remain visible for explicit controller/
operator recovery; no recovery path in this slice fabricates that missing link.
The remaining T08 controller must handle this state visibly before shipping.
The controller and UI now expose this state and remove the submission button;
native operator recovery admission remains in T08.
## Audit Core contract
@ -103,8 +105,9 @@ and auditor identities. That is contract proof, not production custody proof.
Per-class heartbeat generation uses the existing 86,400-second declarations.
It does not emit “nothing to report” for a class with undelivered evidence.
The host must schedule heartbeat generation, bounded draining and monitoring;
no background service or cadence is installed by this source change.
The configured `AuditPump` schedules 30-second ticks, bounded draining and
five-minute reconciliation. The deployment owner must admit its private
storage, credentials and monitoring; no running service was installed here.
## Reconciliation has two time bases
@ -127,18 +130,20 @@ The GH-DEC-2026-014 commitment-only limitation remains.
```sh
INFD_APPROVAL_ENGINE_SOURCE=/home/worsch/approval-engine \
INFD_AUDIT_CORE_SOURCE=/home/worsch/audit-core \
INFD_FLEX_AUTH_BINARY=/absolute/path/to/flex-auth \
uv run python -m pytest -q
```
258 tests pass: 52 added tests cover transactional rollback, process death,
The prior 258-test milestone added 52 tests for transactional rollback, process death,
restore, actor/version/ack guards, concurrent clicks, original correlation,
ambiguous submissions, audit retry/refusal and actual receiver contracts.
The opt-in suites use the actual Approval Engine and Audit Core implementations
with synthetic identity/custody. They make no policy decision and spend nothing.
with synthetic identity/custody. The current 344-test suite also exercises the
actual Flex Auth HTTP server; 12 Chromium checks cover the complete disposable
browser flow. No native credential or paid provider is used.
Remaining under T08: an admitted PDP package/caller and exact read/bind request,
protected review/ack/accept/return/discuss routes, durable policy observations,
visible unresolved-entry recovery, scheduled audit delivery/reconciliation,
native registered human login and deployed-engine/custody proof. No Informed
Remaining under T08: native PDP package/caller/assignment admission against the
[exact consumer contract](flex-auth-review-contract.md), registered human login,
deployed-engine/custody proof and operator recovery/backup admission. No Informed
Decision policy package or registration was found in the checked Flex Auth
examples, registry and docs at `88b3543`; do not substitute a local allow rule.

View file

@ -0,0 +1,81 @@
{
"fixture_only": true,
"browser": "Chromium",
"checks_passed": 12,
"checks": [
"PKCE callback and secure browser session",
"Entitled page escapes memo and packet markup",
"Server refuses bypass of missing acknowledgments",
"Explicit acknowledgment unlocks the form",
"Complete attachment download stays behind entitlement",
"Return records a memo response without an engine entry",
"Mobile review fits the viewport",
"One actual approval entry, stable on browser reload",
"Audit receiver holds all commitments; unsigned decision gap retained",
"Real workload caller refusal hides review content",
"Sign-out clears the session; all forms carry the exact origin",
"No page errors or injected script execution"
],
"fixture_transport": "real HTTPS on ephemeral ports; synthetic issuer and TokenReview",
"native_human_login_proven": false,
"native_policy_admitted": false,
"factory_attempts": 0,
"paid_model_calls": 0,
"final_component_state": {
"entries": 1,
"intents": [
{
"disposition_id": "disp-8ad75d50-1222-4512-a74b-253a15e7d159",
"approval_id": "fixture",
"subject": "human-fixture",
"state": "confirmed",
"attempt": "980d4cd4-753e-40f7-8026-f21923a340fd",
"approved_at": "2026-09-10T22:29:05+00:00",
"presentation_id": "pres-5673438f-ad6c-4ce1-bf26-edfc9211e476",
"operation_id": "c60eaa0c-b627-4f59-8e84-d35fc69d4963"
}
],
"outbox_states": [
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered"
],
"policy_outcomes": [
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"caller_refused"
],
"decision_attributable": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"entry_posts": 1,
"consume_calls": 0,
"tokenreviews": 12
}
}

View file

@ -0,0 +1,93 @@
{
"schema": "informed-decision.protected-browser-review.v1",
"observed_at": "2026-09-10T22:29:50.412419+00:00",
"base_commit": "2cc32168acedb19698fa196911385745fbf897b1",
"contract_source_commits": {
"approval-engine": "a0a602976eef818f36dde35f76f7f2e589bd051b",
"audit-core": "5c0ad522fb36092aa7ec2e8d72f63a5a91853b5b",
"flex-auth": "88b354377c8e26b162f1234e673072f1c06dcd89",
"key-cape": "139994cfac28ff97163ce4bf263f2bb035bbe0a7"
},
"source_task": "INFD-WP-0001-T08",
"source_task_status": "progress",
"verification": {
"command": "INFD_APPROVAL_ENGINE_SOURCE=/home/worsch/approval-engine INFD_AUDIT_CORE_SOURCE=/home/worsch/audit-core INFD_FLEX_AUTH_BINARY=<compiled-flex-auth> make check",
"tests_passed": 344,
"tests_failed": 0,
"tests_skipped": 0,
"new_tests": 86,
"schema_json_valid": true,
"flex_binary_sha256": "c7a1f35aa2cd7cf2733272923ace7fc4b4e55171db4ef8f3d0d6629183dcf1fa",
"browser_checks_passed": 12,
"browser_receipt": "2026-09-11-browser-result.json",
"components": "actual Flex Auth HTTP server with caller enforcement and Approval Engine/Audit Core APIs; synthetic issuer, TokenReview, assignments and credentials"
},
"implemented": [
"fresh pinned PDP checks before render, download and each action, with separate workload caller",
"immutable policy observations and original act binding snapshot; decision_attributable remains false",
"English organizational approval UI with explicit acknowledgments and accept/return/discuss/decline",
"original confirmed entry and visible unresolved state; no automatic mutation retry",
"owner runtime configuration, rotating token file callbacks, scheduled bounded audit delivery and readiness",
"atomic SQLite schema v1-to-v2 upgrade; old UI-release/profile refusal"
],
"browser_findings_fixed": [
"no-referrer produced Origin:null on real form POST; same-origin pages preserve exact-origin CSRF checks"
],
"component_findings_fixed": [
"native caller plain-text 401/403 must remain caller_refused instead of policy_unavailable"
],
"source_sha256": {
"SCOPE.md": "b4568fe033b443d66833d1501fd5b04e01c9d6e95b44bae9666134e914ae758a",
"docs/browser-authentication.md": "9354f8a95914cb353b93256df9e85c455bcf425107f507dd8f1ba6206026794a",
"docs/durable-review-evidence.md": "f7f4a15faa479f3a132120a6fae27837bd2673afda93df7dbd29e8171a7911d0",
"docs/evidence/2026-09-11-browser-result.json": "f405f5d11ae695a9ca8098f6c6a5f125042a62c3af9e87f21bc5e266b6f5a397",
"docs/evidence/2026-09-11-recorded-desktop.png": "89f6e5396094155f2b1e04599f0a2b2d040f4dce004afa4dda752f234eef566a",
"docs/evidence/2026-09-11-review-desktop.png": "e050eceb62cb389d516e4a889c67b1610df3f5539d04efdbafa4874700e90ca3",
"docs/evidence/2026-09-11-review-mobile.png": "3a0b5b1e37b3a54c4eb34688b04bb38b18181b94106b062150fc1b70aa4f3f8a",
"docs/flex-auth-review-contract.md": "3324b7b022fb5397d02520310bf43e0bfbff8c919e95ba9fecc94334dae8caf9",
"docs/protected-browser-review.md": "28f5666a795997db6b6483ab6c3e0c6dab4cc7df948e57f1e5d02e5c45968317",
"informed_decision/approval_http.py": "203f462ff78f1409f2f924d4723197fdd502087c7f6da319f46ffffce2a9d478",
"informed_decision/http_transport.py": "fc9c1fd05cc89120d70bfcdb4c60fe244b81c8054d21505df8cfa9c5a229f7bc",
"informed_decision/memo.py": "697058863a4e6de2c143a2433eaaf5e15e5e7375dc5459af6911b146567e8b5d",
"informed_decision/oidc.py": "35b37bae67968c2179b22af8151afe2981d5468debf4488771eaf3121b75e221",
"informed_decision/policy.py": "7bf814a8332ff054bf5f1f651d8816a408138b1f197b17da0abb7f87411e8812",
"informed_decision/review.py": "c2d2aa1cf48d10d85b3606acf2830ab22701c1274221e5e2760d29901adfd786",
"informed_decision/runtime.py": "6bc6a74657f526743cca6c6cdc0a86fff43d8282e0b867dc9288344636abe5eb",
"informed_decision/store.py": "7a58b36d409cb4161b65985545e13573a5196779b4c6e95ca03ce45c6fada808",
"informed_decision/ui.py": "69fb7fc1794c8842f42e7f0f5a261c4cf64176053ef0a532db46ee6566621219",
"informed_decision/web.py": "00300dc25af3e272db7de748c255f8b1aa0b0182a54f2573e874ed5865da0fd8",
"pyproject.toml": "26e77b2da1ce7d6f1878fb6ca46fdb2acebbad0f6e17f5528d5a1f1d01defe42",
"tests/browser_fixture.py": "31feaf6e3351d9560498ffac2f06cae602f0762a01474bcff2c919c33db3cfcf",
"tests/browser_review.mjs": "0285f2cff70e5d569f31c7e99c8b3a5b5ce98b3eb51c2203de3f2e958f2ac684",
"tests/fixtures/review-policy/fixtures.json": "4c84a411383bfdbd32e15763ce2e934eefec570d93bc68389d6c81d11f3d4243",
"tests/fixtures/review-policy/pin.json": "91c77e4daa0a1c8c394e14e6b0c9d9c493ff21389fefa592656aa363c1104611",
"tests/fixtures/review-policy/policy.md": "cd0a5a79db840e1dad7cabece3976d1683387c71d8a5507476f49b421d180c24",
"tests/fixtures/review-policy/registry.json": "cd358b139f5987dcd0b4c8ac9fffee7d86951b15a22216f6ec21240a51ec41cf",
"tests/review_components.py": "415ef229aedd4def7af737274b4d341ddf4f40a912a8103a017d901b2cdecf2e",
"tests/test_browser_auth.py": "c70e24495d2f968c0a48e4082032666b4f4325f60d7e736c5a27d0fb99ef0f33",
"tests/test_http_transport.py": "d3dcf8051a7acfd152a583f7a865327ae60d880b9b07abc5f5fa9c693e95354e",
"tests/test_policy_client.py": "8ab6f8a06e8b28b4933e0d8d23650c9781a5365343fc4926080c7c2d5e2962ed",
"tests/test_review_component.py": "cd28100fbc66b64703f065c2a3638486043bee5e3e4a6e75de19eb58235f0d47",
"tests/test_review_controller.py": "df3ddfb60dd06728ee871225df96da13462d69f648f214a5ea1b040388c78d53",
"tests/test_review_runtime.py": "e230d9f590b86675b4d42f978cfd2bc769de404b3f5ad510a400ff2fcec62bbd",
"workplans/INFD-WP-0001-founding-specs-and-approver-ui-ownership.md": "49f68a11c301b436655144d4819e827d0ec036fdb2b4463d2679ce8c36cc3b3a"
},
"limits": [
"fixture-only policy; native caller/package/assignment admission pending",
"unsigned decisions remain unattributable under GH-DEC-2026-010 / FLEX-WP-0024",
"no native registration rollout, human login, deployment or audit custody proof",
"English organizational approve profile only; German and wider product acceptance remain T08",
"uncertain entry causation remains unresolved; no reset/retry shortcut",
"audit accepted_at and source occurred_at counts do not prove completeness or reconstructability",
"production packaging, private state, backup/restore and recovery admission pending"
],
"browser_routes_implemented": true,
"native_policy_admitted": false,
"native_human_login_proven": false,
"production_audit_custody_proven": false,
"deployed": false,
"factory_attempts": 0,
"paid_model_calls": 0,
"remaining_live_task": "INFD-WP-0001-T08",
"factory_gate_task": "HFACT-WP-0001-T03"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

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.

View file

@ -0,0 +1,166 @@
# Protected browser review
Implemented under `INFD-WP-0001-T08`, release `0.2.0`. The configured service
now presents one named memo, records explicit highlight acknowledgments and
accept/return/discuss/decline responses, and submits an accepted request to
Approval Engine. This source has passed a disposable Chromium exercise; native
policy, human login, custody and deployment admission remain open.
This first browser profile accepts English, organizational `approve` memos
only. Other locales, weaker steps and AES/QES levels refuse before rendering,
so an English interface cannot attest to a German presentation or imply a
signature level it does not implement. German UI acceptance (PR-60), broader
steps and awareness controls remain T08 product work; the domain model retains
their vocabulary. The initial factory browser proof uses this bounded profile.
## Request and evidence path
1. KeyCape login verifies the human, paired token claims and MFA facts. The
browser holds only an opaque session cookie. The human access token is used
only for Approval Engine and never as the Flex Auth workload credential.
2. `review.py` checks the named recipient and requests a fresh Flex Auth `read`
decision before exposing memo/packet content or calling Approval Engine.
The [consumer contract](flex-auth-review-contract.md) defines all six actions.
3. The immutable policy observation is persisted before use. The returned
package/version/digest, submitted request digest, core binding and lifetime
must match. Unsupported effects/obligations and unavailable callers refuse.
Registry enrichment is observed, never reproduced by this consumer.
4. The live Approval Engine object must declare `human_control=true` and match
the memo's carried act digest. The requesting party and named human approver
remain distinct. The presentation privately retains the observed binding.
5. Every acknowledgment or response obtains another applicable decision. Accept
requires the current memo, required acknowledgments, a live human session,
current audit readiness and an open matching approval. Immediately before
the engine POST, the adapter rechecks the binding and the controller checks
policy/session freshness and reserves the single durable attempt.
6. Acceptance stores the original engine entry correlation. Reload does not
POST again. A lost response, in-flight attempt or unknown duplicate remains
visible and cannot acquire a new presentation link. Return, discussion and
decline record local human responses and never create an engine entry.
The governed canonicalizer remains the sole writer of `view_hash`. No
presentation/acknowledgment fact is submitted to its own permission decision.
Policy observations stay in private content, outside the presentation claim.
`decision_attributable=false` remains explicit: checking the current unsigned
envelope is not GH-DEC-2026-010 decision-path validation (`FLEX-WP-0024`).
The renderer requires `memo.ui_release=informed-decision@0.2.0`. An older memo
must receive a new immutable version; it is not silently relabelled or rendered
as though the old interface produced the current view. Schema v1 databases
migrate atomically to v2 by adding append-only policy observations, preserving
old evidence and submission records.
## Browser surface
| Route | Behavior |
| --- | --- |
| `GET /` | Sign-in or named memo identifier form; no approvals inbox |
| `GET /review?memo_id=...` | Entitled current memo; existing intent retrieves its original view |
| `GET /presentations/<id>` | Entitled historical presentation and current submission result |
| `GET /presentations/<id>/packet/<index>` | Fresh read permission and full attachment bytes |
| `POST /presentations/<id>/ack` | Explicit acknowledgment of selected highlights |
| `POST /presentations/<id>/act` | Accept, return, discuss or decline with an operation id |
Forms require the exact fixed origin and session CSRF token, with bounded bodies
and rejection of duplicate/unknown fields. Session expiry and actor/version
checks apply server-side, including when a user bypasses a disabled button.
The page names the complete request and packet as the object of acceptance.
Highlights do not narrow its scope. Untrusted memo text is escaped, previews
are bounded text, and downloads are attachments with `nosniff`.
Pages use `Referrer-Policy: same-origin`, while authentication paths and
downloads use `no-referrer`. The Chromium test caught that using `no-referrer`
on a form page produces `Origin: null` and rejects legitimate submissions.
Missing, foreign and null form origins remain refused. Cross-origin referrers,
inline scripts, framing and caching remain prohibited. There is no telemetry
or client-side token storage. The reverse proxy must still omit auth queries,
bearer headers and cookies from its logs.
## Owner configuration and audit readiness
Set `INFD_REVIEW_CONFIG` to an absolute, owned, regular 0600 JSON file. Its
parent evidence directory must already exist with mode 0700. Without this
configuration, the entrypoint remains the login shell and `/readyz` stays 503.
The following is a shape example, **not an admitted configuration**; the
placeholders intentionally do not pass validation:
```json
{
"schema": "informed-decision.review-runtime.v1",
"evidence_db": "/OWNER-PRIVATE-PATH/review.sqlite",
"approval_origin": "https://APPROVAL-OWNER-ORIGIN",
"policy": {
"origin": "https://FLEX-OWNER-ORIGIN",
"package": "OWNER-ADMITTED-PACKAGE",
"version": "OWNER-ADMITTED-VERSION",
"package_digest": "OWNER-ADMITTED-SHA256",
"caller_token_file": "/OWNER-PROJECTED-PATH/flex-caller-token"
},
"audit": {
"origin": "https://AUDIT-OWNER-ORIGIN",
"sender_token_file": "/OWNER-PRIVATE-PATH/audit-sender-token"
}
}
```
`INFD_KEYCAPE_ISSUER` remains mandatory. Credential files are read afresh when
needed, so projected rotation does not require storing a token in configuration
or SQLite. Runtime loading provisions nothing. Fixed internal `.svc` origins
are supported explicitly; public cleartext origins and redirects are refused.
The server remains one Waitress process, loopback port 8080, four threads.
Multi-replica sessions/storage and deployment packaging require separate work.
The audit thread ticks every 30 seconds, generates the declared per-class
heartbeats, drains at most ten records per tick and writes a private
`audit-reconciliation.json` at most every five minutes. A successful drain and
reconciliation with no retained delivery debt make readiness current for 90
seconds. Errors or blocked records clear readiness; accept refuses while it is
closed. This is a process/delivery health signal, not an assertion of native
policy admission or authorization. Dispositions still persist transactionally.
Credential/schema refusals need operator repair and explicit requeue; no failed
event is discarded. Source `occurred_at` and receiver `accepted_at` are retained
as different count windows, without an automatic loss or completeness claim.
An independent auditor reads the receiver in component tests. Production
sender/receiver custody, backup/restore and reconciliation procedures remain
admission work under T08 and `AUDIT-WP-0009-T11`.
Uncertain entry recovery must preserve causation. Finding a later entry is
insufficient because Approval Engine stores no caller presentation/operation
id. Inspect the original immutable intent and independent evidence; never reset
an unresolved attempt merely to make the button available. If causation cannot
be established, keep it unresolved and obtain an owner-directed disposition of
the approval. This UI offers no shortcut that fabricates the missing link.
## Reproduce the component and browser checks
Build the checked Flex Auth source with its own `go build ./cmd/flex-auth`, then
set explicit source paths and the resulting binary:
```sh
export INFD_APPROVAL_ENGINE_SOURCE=/path/to/approval-engine
export INFD_AUDIT_CORE_SOURCE=/path/to/audit-core
export INFD_FLEX_AUTH_BINARY=/absolute/path/to/flex-auth
make check
```
With the Python dev dependencies, Playwright and Chromium installed, start
`PYTHONPATH=. python tests/browser_fixture.py /tmp/infd-browser-UNIQUE` and run
`node tests/browser_review.mjs /tmp/infd-browser-UNIQUE` in another terminal.
`INFD_PLAYWRIGHT_PACKAGE` can name an installed Playwright package, and
`INFD_CHROMIUM_EXECUTABLE` can name its Chromium executable. The driver stops
the fixture and writes the result plus desktop/mobile screenshots.
The harness uses real local HTTPS, browser redirects/forms/cookies, the actual
Flex Auth server with enforced caller authentication, and the actual Approval
Engine/Audit Core APIs with separate SQLite stores. Its issuer, TokenReview,
policy assignments, identities, credentials and act are synthetic. Browser
hostnames resolve to loopback; only the fixture certificate's public key is
trusted by the override. The harness control endpoints live only in tests.
Exact production callback/registration strings remain covered separately.
The result covers login, escaped content, acknowledgment bypass refusal,
explicit acknowledgment, packet download, return, mobile fit, a single accepted
entry/reload, receiver delivery, workload caller refusal, sign-out and absence
of script execution. It proves no native human login, production policy/custody,
deployed UI or factory execution. See the dated JSON evidence for exact sources.