Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
9.4 KiB
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
- 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.
review.pychecks the named recipient and requests a fresh Flex Authreaddecision before exposing memo/packet content or calling Approval Engine. The consumer contract defines all six actions.- 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.
- The live Approval Engine object must declare
human_control=trueand match the memo's carried act digest. The requesting party and named human approver remain distinct. The presentation privately retains the observed binding. - 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.
- 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:
{
"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 require separate work. Single-writer container
packaging and the review-only deployment packet are now supplied in
deploy/README.md; publication and native rollout remain open.
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:
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.