diff --git a/Containerfile.memo-input b/Containerfile.memo-input index 3adb3f8..b53fd79 100644 --- a/Containerfile.memo-input +++ b/Containerfile.memo-input @@ -1,3 +1,4 @@ # Minimal repair on the admitted runtime; build with the repository as context. FROM forgejo.coulomb.social/coulomb/informed-decision@sha256:8f55bcecf37a8d65f96e073510b1ffb4636c0a91d75e1ee7d582ad4bce8b953a COPY --chown=10001:10001 informed_decision/web.py /opt/venv/lib/python3.12/site-packages/informed_decision/web.py +COPY --chown=10001:10001 informed_decision/oidc.py /opt/venv/lib/python3.12/site-packages/informed_decision/oidc.py diff --git a/Containerfile.memo-input.dockerignore b/Containerfile.memo-input.dockerignore new file mode 100644 index 0000000..dc5d0c1 --- /dev/null +++ b/Containerfile.memo-input.dockerignore @@ -0,0 +1,5 @@ +** +!informed_decision/ +informed_decision/* +!informed_decision/web.py +!informed_decision/oidc.py diff --git a/deploy/t03-admission.json b/deploy/t03-admission.json index 0ae98f0..c62302f 100644 --- a/deploy/t03-admission.json +++ b/deploy/t03-admission.json @@ -1,5 +1,5 @@ { - "image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:ef6fdd61209863654be3adba070661645a2714e86cb4b7f4e847540291b55f07", + "image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:d08bdced387a3f24bac0c735d91ad4e2d0ed50cd96e58431343a60eee6421d82", "policy": { "origin": "http://flex-auth-informed-decision-t03.flex-auth.svc.cluster.local:8080", "package": "informed-decision.t03-review", diff --git a/docs/evidence/2026-09-16-review-fresh-authentication.json b/docs/evidence/2026-09-16-review-fresh-authentication.json new file mode 100644 index 0000000..e8ec45a --- /dev/null +++ b/docs/evidence/2026-09-16-review-fresh-authentication.json @@ -0,0 +1,12 @@ +{ + "task": "SECRETS-WP-0010-T03", + "observation_id": "9e56e4a1-70e4-4055-9510-6734fb6357b2", + "observed_at": "2026-09-15T23:32:13.223283+00:00", + "authentication_at": "2026-09-15T23:15:12+00:00", + "authentication_age_seconds": 1021.223283, + "policy_maximum_age_seconds": 900, + "finding": "The exact memo, version, approval binding, human identity, group, tenant provenance and MFA shape match; freshness exceeds policy allowance. Review login omitted prompt/max_age and allowed older KeyCape SSO authentication to be reused.", + "change": "Request prompt=login and max_age=0 from KeyCape; preserve signed assurance timestamps and policy freshness requirement.", + "validation": "119 browser and review tests passed with local Approval Engine component; existing KeyCape TestFreshLoginRequirementsReachProvider covers forwarding these parameters. Live human reauthentication remains to be performed by the operator.", + "image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:d08bdced387a3f24bac0c735d91ad4e2d0ed50cd96e58431343a60eee6421d82" +} diff --git a/informed_decision/oidc.py b/informed_decision/oidc.py index d61fb51..201535b 100644 --- a/informed_decision/oidc.py +++ b/informed_decision/oidc.py @@ -78,6 +78,8 @@ 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, + # Review policy requires recent MFA; a reused SSO session may be older. + "prompt": "login", "max_age": "0", "code_challenge": challenge, "code_challenge_method": "S256", }), browser diff --git a/tests/test_browser_auth.py b/tests/test_browser_auth.py index b8f873a..345d572 100644 --- a/tests/test_browser_auth.py +++ b/tests/test_browser_auth.py @@ -101,6 +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 login[1].params["prompt"] == "login" + assert login[1].params["max_age"] == "0" assert login[1].params["nonce"] != login[1].params["state"]