Request fresh KeyCape login for timed reviews with narrow image candidate

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a1029c-c003-7283-acc9-930b434e6cae
This commit is contained in:
tegwick 2026-10-03 20:33:34 +02:00
parent 219d83ad1b
commit 2d2161bc64
7 changed files with 83 additions and 7 deletions

6
Containerfile.fresh-auth Normal file
View file

@ -0,0 +1,6 @@
# Narrow repair of the admitted review image; excludes pending intake changes.
FROM forgejo.coulomb.social/coulomb/informed-decision@sha256:0557edffb0efccc2e283cb878bc3f85deacd8165b45eefde830c21f6f02710c8
ARG SOURCE_REVISION
LABEL org.opencontainers.image.revision=$SOURCE_REVISION
LABEL org.opencontainers.image.base.digest="sha256:0557edffb0efccc2e283cb878bc3f85deacd8165b45eefde830c21f6f02710c8"
COPY informed_decision/oidc.py /opt/venv/lib/python3.12/site-packages/informed_decision/oidc.py

View file

@ -57,6 +57,15 @@ MFA `at` is preserved as authentication time. A successful login does not assert
that MFA meets an action-specific freshness policy; the policy integration must
use these facts for the action. No local approval verdict is inferred.
Review sign-in requests `prompt=login` and `max_age=0` from KeyCape. Its
`KEY-WP-0033` implementation translates those parameters for Authelia 4.38 and
enforces the exact requested freshness against verified upstream authentication
time. It also refuses to reuse the existing KeyCape assurance for that login.
The earlier rollback predated this owner fix. Review policy still independently
requires signed MFA within 900 seconds; neither login nor token mint time
replaces authentication time. Portal sign-in does not refresh an existing review
session: start review sign-in again after authenticating elsewhere.
Sessions last at most fifteen minutes and never outlive either token. They are
bounded to 1,024 entries, protected by a process lock, rotated on sign-in and
deleted on sign-out/expiry. Restart requires reauthentication. This is a

View file

@ -9,7 +9,7 @@
"mfa_age_at_request_seconds": 4781,
"maximum_mfa_age_seconds": 900,
"identity_and_memo_pins_match": true,
"fresh_password_and_otp_on_latest_attempt": "awaiting operator confirmation",
"fresh_password_and_otp_on_latest_attempt": "Founder reports logout through users.coulomb.social followed by password and OTP login in the same browser; review request still carries the old signed time.",
"dependency": "INFD-IN-0005",
"next_step": "Complete KeyCape /account/logout and upstream browser sign-out, then fresh password/OTP login. If the signed authentication time remains old after real OTP, KeyCape owns the correction and completed-browser proof.",
"policy_relaxed": false,

View file

@ -78,8 +78,10 @@ class KeyCapeLogin:
return self.issuer + "/authorize?" + urlencode({
"response_type": "code", "client_id": CLIENT_ID, "redirect_uri": CALLBACK,
"scope": " ".join(REQUIRED_SCOPES), "state": state, "nonce": nonce,
# Authelia 4.38 cannot complete prompt=login/max_age=0.
# Review policy still enforces the signed MFA authentication age.
# KeyCape enforces freshness itself and translates the upstream
# request for Authelia 4.38 (KEY-WP-0033). Prevent a reused issuer
# session from carrying stale MFA into a new review login.
"prompt": "login", "max_age": "0",
"code_challenge": challenge, "code_challenge_method": "S256",
}), browser

View file

@ -101,8 +101,8 @@ def test_pkce_nonce_scope_and_imported_human_session(login):
assert session.access_token not in repr(session)
assert login[1].params["scope"] == "openid approval:read approval:approve"
assert login[1].params["code_challenge_method"] == "S256"
assert "prompt" not in login[1].params
assert "max_age" not in login[1].params
assert login[1].params["prompt"] == "login"
assert login[1].params["max_age"] == "0"
assert login[1].params["nonce"] != login[1].params["state"]

View file

@ -118,8 +118,9 @@ A6 refusal diagnosis: read at 18:27:49 UTC still carried exactly the same
KeyCape `assurance.at=1791047288` (17:08:08 UTC), age 4,781 seconds. Exact
identity, group, memo and native approval pins match v7; the 900-second MFA
limit refuses this request. The latest attempt has not supplied fresh evidence;
whether the browser actually performed a fresh OTP is awaiting operator
confirmation. Do not infer a new authentication from a successful redirect.
the founder confirms account-portal logout followed by password and OTP login
in the same browser. That did not propagate fresh assurance into this review
request. Do not infer a new review authentication from portal login.
KeyCape's `/account/logout` confirmation clears its session and routes through
upstream Authelia sign-out; informed-decision sign-out alone is local. Complete
that browser flow, then start a new review login with password and OTP.
@ -127,3 +128,5 @@ If the verified timestamp remains old after that, KeyCape must correct the
authentication-time contract under existing intake `INFD-IN-0005` and prove
it with a completed browser journey. Retain all policy freshness limits.
Evidence: `docs/evidence/2026-10-03-provisioning-window-review-refusal.json`.
`INFD-WP-0006` implements an explicit fresh-authentication request from review
sign-in; its narrow image rollout and native browser proof remain blocked.

View file

@ -0,0 +1,56 @@
---
id: INFD-WP-0006
type: workplan
title: "Request fresh issuer authentication for timed decision reviews"
domain: infotech
repo: informed-decision
status: blocked
owner: codex
created: "2026-10-03"
updated: "2026-10-03"
related: [INFD-IN-0005, KEY-WP-0033, INFD-WP-ADHOC-2026-10-03]
---
## Request fresh authentication on review sign-in
```task
id: INFD-WP-0006-T01
status: done
priority: high
```
The founder reported signing out through users.coulomb.social and entering
password and OTP again in the same browser, but p01 read still carried the
17:08:08 UTC authentication time. Portal and review sessions are independent.
Review sign-in currently permits reused KeyCape assurance. Request
`prompt=login` and `max_age=0` via the existing state/nonce/PKCE flow, using
KeyCape's completed KEY-WP-0033 compatibility implementation. Retain the
signed authentication timestamp and every action policy freshness check.
Update the existing browser authentication regression and document the owner
contract. No new identity assertion or local authorization decision.
Implemented and validated: all 80 browser-authentication tests pass, including
preservation of the issuer's original signed authentication time. The candidate
uses `Containerfile.fresh-auth` to replace only `oidc.py` in the exact admitted
image, excluding pending intake implementation and schema migration. Native
browser proof remains T02.
## Deploy and prove the fresh browser journey
```task
id: INFD-WP-0006-T02
status: wait
priority: high
needs_human: true
blocking_reason: "Publish and prepare a pinned review image, obtain founder approval for the live rollout, then complete human password/OTP login and verify a new signed authentication time and p01 read allowance."
```
Source tests are insufficient for native admission. Publish the exact tested
source and prepare the existing deployment image update with previous image
rollback; preserve runtime policy and memo pins. Live replacement needs the
founder's go under the agent environment orientation attended-window rule.
The founder alone completes password/OTP and any disposition. Verify the
signed timestamp is new and exact p01 read is allowed. If genuine fresh MFA
still reports the prior time, KeyCape must correct assurance issuance under
INFD-IN-0005; if its upstream freshness check fails, KeyCape/Authelia own that
dependency. Do not increase the 900-second action limit to mask either issue.