Require fresh KeyCape authentication for decision review sign-in

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a09cbb-87c6-7900-a145-4ce53ba9f1a6
This commit is contained in:
tegwick 2026-09-16 01:35:02 +02:00
parent c70d63abf9
commit 3f1c9ecd8a
6 changed files with 23 additions and 1 deletions

View file

@ -1,3 +1,4 @@
# Minimal repair on the admitted runtime; build with the repository as context. # Minimal repair on the admitted runtime; build with the repository as context.
FROM forgejo.coulomb.social/coulomb/informed-decision@sha256:8f55bcecf37a8d65f96e073510b1ffb4636c0a91d75e1ee7d582ad4bce8b953a 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/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

View file

@ -0,0 +1,5 @@
**
!informed_decision/
informed_decision/*
!informed_decision/web.py
!informed_decision/oidc.py

View file

@ -1,5 +1,5 @@
{ {
"image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:ef6fdd61209863654be3adba070661645a2714e86cb4b7f4e847540291b55f07", "image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:d08bdced387a3f24bac0c735d91ad4e2d0ed50cd96e58431343a60eee6421d82",
"policy": { "policy": {
"origin": "http://flex-auth-informed-decision-t03.flex-auth.svc.cluster.local:8080", "origin": "http://flex-auth-informed-decision-t03.flex-auth.svc.cluster.local:8080",
"package": "informed-decision.t03-review", "package": "informed-decision.t03-review",

View file

@ -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"
}

View file

@ -78,6 +78,8 @@ class KeyCapeLogin:
return self.issuer + "/authorize?" + urlencode({ return self.issuer + "/authorize?" + urlencode({
"response_type": "code", "client_id": CLIENT_ID, "redirect_uri": CALLBACK, "response_type": "code", "client_id": CLIENT_ID, "redirect_uri": CALLBACK,
"scope": " ".join(REQUIRED_SCOPES), "state": state, "nonce": nonce, "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", "code_challenge": challenge, "code_challenge_method": "S256",
}), browser }), browser

View file

@ -101,6 +101,8 @@ def test_pkce_nonce_scope_and_imported_human_session(login):
assert session.access_token not in repr(session) assert session.access_token not in repr(session)
assert login[1].params["scope"] == "openid approval:read approval:approve" assert login[1].params["scope"] == "openid approval:read approval:approve"
assert login[1].params["code_challenge_method"] == "S256" 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"] assert login[1].params["nonce"] != login[1].params["state"]