diff --git a/docs/evidence/2026-09-13-p04-recovery.md b/docs/evidence/2026-09-13-p04-recovery.md index 35cc7c9..e9c2872 100644 --- a/docs/evidence/2026-09-13-p04-recovery.md +++ b/docs/evidence/2026-09-13-p04-recovery.md @@ -11,7 +11,7 @@ Recovery disables one selected factor and preserves password, directory identity tenant access and other factors. Provider audit persists before mutation; stale state, changed ownership and conflicting references are rejected. PostgreSQL advisory locking serializes recovery requests; row locking protects the selected -factor and a final fingerprint protects readback. Retries reconcile completion. +factor and its ownership records and a final fingerprint protects readback. Retries reconcile completion. Check recovery result by support reference if the page or response was lost; the original administrator can obtain a fresh confirmation for an interrupted operation. A completed receipt is rechecked against current provider state. @@ -34,10 +34,10 @@ before AAL2. Recovery does not automatically relax application MFA policy. ## Release and verification -- Portal source: 11dfaf5 (including 58e07dd). -- Portal image: forgejo.coulomb.social/coulomb/user-engine@sha256:86112f2f0bb6388344d0260a3611da2a19c609b8f08bd79858d51e1a271e5fa6. -- Provider service source: key-cape d15f4dd (including cb51584). -- Immutable service code: mfa/factor-recovery-626517ff9acb0ef7. +- Portal source: c298cd9 (including 11dfaf5 and 58e07dd). +- Portal image: forgejo.coulomb.social/coulomb/user-engine@sha256:c71c6653132611de0c5f1209ca641ecefcde0df49a824930c6365a9fdecd3235. +- Provider service source: key-cape 63b3070 (including d15f4dd and cb51584). +- Immutable service code: mfa/factor-recovery-79e2964c112f3688. - Provider image: ghcr.io/gpappsoft/privacyidea-docker@sha256:af7841adad262f129e0c1d4f553af13f21cb2f4dc713533f316cfe43ed0b4473. - net-kingdom deployment procedure: sso-mfa/k8s/privacyidea/deploy-factor-recovery.py; possession policy: enable-factor-confirmation.py. Cluster and deployment UID @@ -46,12 +46,14 @@ before AAL2. Recovery does not automatically relax application MFA policy. - 15 recovery core/service tests passed, including lost-confirmation reconciliation. - 19 isolated Chromium checks passed, including P04 role denial, scope/proof confirmation, completion receipt and replacement instructions. -- Installed-provider Job provider-p04-contract-02 passed signed administrator +- Installed-provider Job provider-p04-contract-03 passed signed administrator recovery, wrong role/audience, stale MFA, unsigned requests, unknown-user - isolation, tampered confirmation, durable audit, retry, reference readback, + isolation, multi-owner factor refusal, tampered confirmation, durable audit, retry, reference readback, replacement possession and authentication. Its databases, identities, JWT signing key and OTP seeds were disposable fixtures, not production accounts. -- Exact source CI passed: KeyCape run60; portal runs161/162/163. +- Exact source CI passed: KeyCape run61; portal runs166/167/168. +- Native PostgreSQL advisory and token/ownership locking queries passed against + a nonexistent token ID and were rolled back; no factor rows were changed. - Both deployments completed rollout. Live portal health/readiness returned 200; anonymous recovery page returned 403 with sign-in recovery navigation. Native portal-to-provider health returned 200; missing/invalid authentication returned @@ -61,3 +63,7 @@ No real user's authenticator was disabled for testing. Production authenticated recovery was not exercised against a real account; positive mutation and browser acceptance used disposable fixtures. P05 service operations and P06 broader policy/self-service work remain USER-WP-0030-T03; P04 is removed from that gap. + +Shared factors (one serial assigned to multiple identities) are explicitly refused +before mutation, with a clear ownership-resolution message. This preserves the +bounded single-identity recovery contract.