key-cape/workplans/KEY-WP-0040-mfa-attended-run-findings.md

163 lines
8.8 KiB
Markdown
Raw Normal View History

---
id: KEY-WP-0040
type: workplan
title: "Fix findings from the first attended MFA run (factor recovery preview, OTP prompt help)"
domain: infotech
repo: key-cape
status: finished
owner: claude-code
topic_slug: netkingdom
created: "2026-10-11"
updated: "2026-10-17"
flavor: implementation
depends_on: []
state_hub_workstream_id: "a67f9d60-9b8f-5111-9fe5-9f64e631b1c3"
---
From the attended run of 2026-10-11 (user-engine `docs/evidence/2026-10-11-mfa-attended-u05-u08.md`).
U05–U07 passed. U08 is blocked by T01.
## Recovery preview rejects valid input (F6)
```task
id: KEY-WP-0040-T01
status: done
priority: high
state_hub_task_id: "b385602d-714a-5fdb-b40b-bd870420f28e"
```
Operator `platform-root` (holds platform-operator, fresh AAL2) previewed login `tegwick`,
reference `U08-2026-10-11` at `/platform/factor-recovery`. Every attempt returned `invalid_request`
("Enter a valid login and support reference."). Both inputs match `[A-Za-z0-9_.@:/-]{1,150}`.
The `factor-recovery` container in `mfa/privacyidea` logged nothing.
Candidate causes in `scripts/recovery_service.py` / `scripts/factor_recovery.py`:
- the actor `sub` (KeyCape `user.ID`) failing `_recover`'s character rule;
- a privacyIDEA serial failing it;
- the request body differing from what is validated, e.g. form encoding through the portal.
Done when:
- the failing check is identified and fixed with a regression test;
- the sidecar logs the failing check (field name and error code, never values);
- a preview for `tegwick` lists the active TOTP (serial suffix …E1D) without applying anything.
Then hand back to user-engine, which re-runs U08 (USER-WP-0028-T03). The fix and roll-out
of the sidecar are blue lane under the build-mode change rule.
2026-10-12 source repair: LLDAP adapter returns entry.DN as user.ID and the token
issuer emits that exact value as sub. Recovery incorrectly applied the login
regex to actor, rejecting comma/equal characters. Two DN-shaped subject tests
reproduce invalid_request against the old source. The repair validates the
bounded printable ASCII actor separately, preserves exact ticket/audit binding,
and keeps target/serial/realm/reference validation strict. Validation diagnostics
emit only closed field names and error codes to stderr; provider logging stays
disabled. Twenty recovery tests pass, including identity switching, malformed
input, provider field failures, replay and mutation/audit guards. Go OIDC and
LLDAP suites pass. No live factor was read or changed. T01 stays progress until
the deployed authenticated preview succeeds and user-engine can rerun U08.
## Link the OTP prompt to lost-authenticator help (F3)
```task
id: KEY-WP-0040-T02
status: done
priority: medium
state_hub_task_id: "3ad155dd-15ef-5522-bdf9-c78832728553"
```
The OTP input offers no way out for a user whose code is rejected or whose device is lost. Add
"Code rejected or lost your authenticator?" linking to
`https://users.coulomb.social/security` (the lost-authenticator section). The same link serves users
who have no factor yet (the dead end noted in `mfa-attended-run.md`).
2026-10-12: source link added to the MFA challenge with noreferrer, preserving
challenge state and requiring no query/token in the destination. Go OIDC tests
pass. Runtime publication and attended journey verification remain open; T02
is not represented as deployed.
2026-10-12 blue-lane runtime repair completed: immutable ConfigMap
factor-recovery-01119187d90d7b76 replaced only the recovery-code volume through
UID/resourceVersion CAS. Server dry-run proved no other pod-template change.
privacyIDEA generation 11 is Ready; recovery health returns 200 and anonymous
recovery is denied (403). All Go tests pass in the actual checkout. An early
ready=false observation was retained while the rollout completed; no apply was
replayed. Abort owner: key-cape; rollback restores prior immutable ConfigMap
factor-recovery-79e2964c112f3688 with the same CAS helper. Receipt and exact
proposal: the-custodian/docs/evidence/2026-10-12-netkingdom-security/.
T01 remains progress for the founder's authenticated tegwick preview and U08.
T02 is a local source edit only; its source/image publication remains pending.
2026-10-14: the MFA challenge render test now requires the lost-authenticator
link after the OTP form, with rel="noreferrer" and no request state in the URL.
T02 stays progress until that page is published and an attended journey sees it.
## Current publication and attended acceptance — 2026-10-16
The source-only publication statements above describe the October 12–14 state.
They are superseded for T02: the October 15 founder-run publication recorded in
`docs/operations.md` (Current image) and KEY-WP-0041-T02 delivered image
`sha256:cdec9dd7c515f7e0a6169fc3fa560ee2cc47bf40d899755dec808c362f5ce010`
from source `8c6c071`. That source includes the OTP help link commit `205a1c0`.
The founder verified the image-only diff, server dry-run, Recreate rollout,
Ready pod with zero restarts and discovery HTTP200. No additional image rollout
is needed to make the existing T02 link available. This reconciliation makes
no new live observation and does not infer attended acceptance from publication.
T01 still needs the actual authenticated preview; T02 still needs the actual
OTP-page observation. Both remain progress. Resume the existing owner procedure
`user-engine/docs/mfa-attended-run.md`, corrected by its October 11 evidence
`user-engine/docs/evidence/2026-10-11-mfa-attended-u05-u08.md`:
1. In the real user-engine-portal OTP challenge, observe **Code rejected or lost
your authenticator?**, follow it to `https://users.coulomb.social/security`,
and confirm the rejected-code/lost-device guidance is reachable. Preserve no
challenge URL, request state, cookie or OTP value in evidence. Record time,
client, link text/destination and outcome. This supplies T02 acceptance.
2. With platform-root's own fresh AAL2 browser session, open the existing
`/platform/factor-recovery` form. Preview `tegwick` using the existing support
reference `U08-2026-10-11`; inspect any existing reference before changing it.
Confirm the current factor metadata and shared-identity warning. The October
11 suffix was …E1D; a changed factor is a reason to reconcile current state,
never to force the old selection. Record only time, preview outcome and serial
suffix. This preview alone makes no factor change and supplies the remaining
T01 preview evidence.
3. Only in the separately attended recovery window, after the operator verifies
the person and exact current scope, continue the existing U08 confirmation,
audited disable, reference readback, replacement enrollment and fresh login
procedure. Preserve the original reference and safe recovery record id.
Neither the published bug fix nor a passing preview closes U08. Stop on
stale metadata, replaced factor or failed audit/readback; do not reset or
re-enroll merely to make an acceptance check pass.
No authenticated preview, real-factor mutation or attended page observation was
performed during this source reconciliation. No passwords, codes, token values,
provider keys or production Secret objects were requested or read.
## T02 attended acceptance — 2026-10-17
The founder reported in session that the real user-engine-portal OTP challenge
shows **Code rejected or lost your authenticator?**, that it leads to
`https://users.coulomb.social/security`, and that the lost-device guidance is
reachable there ("T02 is fine"). This is the founder's own observation, on the
deployed image `cdec9dd7` from source `8c6c071`. No exact time or client was
recorded, and no challenge URL, request state, cookie or OTP value was preserved.
T02 is done. T01 still waits for the authenticated preview (step 2 above).
## T01 attended preview acceptance — 2026-10-17
The founder, signed in as platform-root with its own fresh OTP (AAL2), opened
`/platform/factor-recovery` and previewed login `tegwick` with the existing
reference `U08-2026-10-11`. The founder reported that the preview listed
tegwick's TOTP. The `invalid_request` failure from October 11 (F6) did not recur.
No confirm or disable action was taken, and no factor was changed. When asked
afterwards, the founder confirmed that the listed TOTP's serial suffix is …E1D,
the same active factor as on October 11. The exact time was not recorded.
All three Done-when conditions now hold: the DN-shaped actor defect was fixed
with regression tests (2026-10-12); the sidecar logs only closed field names and
error codes; and the deployed preview for tegwick lists the active TOTP …E1D
without applying anything. That third condition was met only after the suffix
was confirmed, not before. T01 and the workplan are done. U08 itself, meaning
the attended disable, re-enrolment and fresh login, belongs to user-engine
(USER-WP-0028-T03) and is handed back to it. This workplan does not close U08.