diff --git a/docs/account-journeys.md b/docs/account-journeys.md index 3978454..e60fc74 100644 --- a/docs/account-journeys.md +++ b/docs/account-journeys.md @@ -68,7 +68,7 @@ headless capability alone does not mean a journey is usable or verified live. | P02 — Create tenant and first administrator | Confirm tenant identifier/type/name and first admin; show tenant created versus admin onboarding pending | Conflict/partial failure readback avoids duplicate tenant; resume only missing stages | Existing platform creation/result routes; live end-to-end drill pending | | P03 — Find and inspect a tenant | Search exact identifier or disambiguate matching names; clearly state selected scope | Unknown/ambiguous name presents choices without guessing authority | Existing tests for unknown/ambiguous names and tenant selection | | P04 — Recover a tenant administrator | Verify request and affected scope; audited, bounded account/factor recovery returns control | Insufficient proof denies; provider outage yields pending state and named owner | Implemented: recent-MFA platform recovery, exact-factor confirmation, durable provider audit/readback/retry and replacement possession; see evidence/2026-09-13-p04-recovery.md | -| P05 — Operate sign-in, factor and notification services | See degraded component and impacted journeys; renew scoped credentials; verify recovery | Expired factor-read credential blocks assurance decision; missing mail uses explicit assisted setup; no hidden MFA bypass | Factor-read custody, automatic renewal and mounted delivery verified (RPF-WP-0040); provider expiry/revocation drills and mail delivery remain open | +| P05 — Operate sign-in, factor and notification services | See degraded component and impacted journeys; renew scoped credentials; verify recovery | Expired factor-read credential blocks assurance decision; missing mail uses explicit assisted setup; no hidden MFA bypass | Implemented and deployed (USER-WP-0032): checked services, confirmed single-delivery recovery, durable uncertain-send guard; SMTP/IMAP retry and provider expiry/permission/rotation acceptance pass; live checks send no email | | P06 — Set authentication policy | Distinguish optional-after-enrollment, mandatory, and application step-up; preview impact and rollback | Unsupported/ambiguous policy rejected; avoid locking out unenrolled users or weakening privileged actions | KeyCape optional policy source tested; scoped rollout and privileged-portal policy acceptance pending | | P07 — Suspend/retire/reactivate tenant | Confirm blast radius and resulting tenant lifecycle; applications reflect effective policy | Stale version or partial propagation provides readback/retry; recovery retains audit | Existing tenant lifecycle APIs; browser confirmation/propagation drill pending | | P08 — Review audit and service recovery | Follow correlation reference without exposing secrets; see actor, tenant, action and result; prove rollback | Missing telemetry or unknown state visible; no success until authoritative readback | Existing service events/references; unified browser audit/support workflow pending | diff --git a/docs/evidence/2026-09-13-p05-service-operations.md b/docs/evidence/2026-09-13-p05-service-operations.md new file mode 100644 index 0000000..e653ef0 --- /dev/null +++ b/docs/evidence/2026-09-13-p05-service-operations.md @@ -0,0 +1,89 @@ +# P05 service operations acceptance — 2026-09-13 + +USER-WP-0032 implements P05 under USER-WP-0030-T03. P06 remains separate. + +## Operator journey + +Platform administration → Service recovery displays bounded checks for directory, +primary sign-in, authenticator provider, mounted factor-read credential, mail store +and SMTP authentication. Each has impact and recovery guidance. Checks submit no +email. Provider acceptance, inbox receipt and functional sign-in are distinct. + +Find one delivery by ID or support reference. Review delivery attempt presents a +CSRF/session-bound confirmation of that exact record. Changing state invalidates +confirmation. Failed claims are released, completed records cannot be submitted +again, and event operations serialize across DB connections. Queueing alone does +not send; no background production backlog processor was enabled. + +Selected invitation records show mail evidence from the existing authenticated +mail lane. Durable per-event mail reservations survive process restart and lost +post-send writes. Definitely failed attempts can be retried. Uncertain SMTP +outcomes block resending and require provider reconciliation or assisted account +setup. Provider errors are classified; raw exception text is not stored/shown. + +## Automated acceptance + +- Full portal suite against disposable PostgreSQL: **227 passed, zero skips**, + including two independent connections submitting one event exactly once. +- Browser suite: **23 checks passed**, including selected review, failure, + retry, completed-send guard and visible receipt limits. +- email-connect: **89 tests passed**, including real loopback GreenMail SMTP/IMAP, + uncertain post-send write/restart and SMTP QUIT failure regression. +- `scripts/p05_mail_acceptance.py`: portal → HTTP adapter → email-connect → + real SMTP/IMAP, deliberately failed audit response, confirmed retry; exactly + one test message received and both delivery lanes finally accepted. +- KeyCape full Go suite passed. Installed-provider Job + `mfa/provider-p05-contract-01` passed genuine JWT expiry, fresh-session recovery, + expired predecessor rejection, permission withdrawal/recovery and existing + enrollment/replacement/recovery contract in isolated SQLite/audit databases. +- Native `scripts/keycape_factor_acceptance.py` passed Job + `keycape-factor-proof-91ea82cd`: wrong service account, issuer-password and + sibling-secret denials; mounted custody match; per-user lookup acceptance; + provider-administration denial; mounted rotation acceptance; proof-session + revocation. Renewal Job `keycape-factor-rotate-91ea82cd` succeeded. + +Reproduce portal DB tests with USER_ENGINE_POSTGRES_TEST_DSN and +USER_ENGINE_POSTGRES_TEST_RESET=1 pointing only at a disposable PostgreSQL DB. +Run `make test-browser-journeys`. For SMTP acceptance, start the email-connect +GreenMail harness, then run `PYTHONDONTWRITEBYTECODE=1 python3 +scripts/p05_mail_acceptance.py` with sibling email-connect source available. +GreenMail image used: `greenmail/standalone:2.1.12@sha256:9f32971b4f25d32b4de6fa2e297423768441c65e4541f6aecd7631c890a229a7`. + +## Evidence ceiling and rollback + +All sent messages used loopback test mailboxes. Live validation is non-sending; +no production invitation or backlog was processed. Registration OTP/client policy +and real invited-person email receipt remain their own user/P06 journeys. + +Mail schema changes are additive. Preserve send_attempts and deliveries. Before +rolling email-connect back to a pre-P05 image, stop delivery and reconcile any +in_flight reservations: older code does not enforce this duplicate-send guard. +Portal/KeyCape rollback preserves existing credentials/configuration. Replacing +KeyCape's single issuer instance may require restarting an in-progress sign-in. + +## Release and live readback + +All source/image CI passed: user-engine runs 170/171/172, KeyCape 62/63, +email-connect 24/25/26. Exact CI-built images: + + +- user-engine source `ac0eb14`: `forgejo.coulomb.social/coulomb/user-engine@sha256:8c55d285123c70c453752e19fa1b0ed179cb7fe060e854040fa1c559748a1ebf` +- key-cape source `aa709fb`: `forgejo.coulomb.social/coulomb/key-cape@sha256:d3c358ec793b59d519ea6b1dbe4172449745a57504474399984de6cd8703024d` +- email-connect source `8984a84`: `forgejo.coulomb.social/coulomb/email-connect@sha256:e095d7e51c68a29ff6b82d735c734d5d27e0041b937dc958ecee5bcb5ddf5e8b` + +All three deployments rolled out successfully. Portal public /healthz and /readyz +and KeyCape /readyz return 200. Anonymous /platform/operations returns 403. +The running portal queried both dependencies with its existing service credentials: +LLDAP, Authelia, privacyIDEA and factor_reader all report ok; mail database and +SMTP authentication both report ok, message_sent=false and +inbox_receipt_verified=false. No credential values were printed or copied. + +Email invitation URL is corrected from the historical nip.io address to +https://users.coulomb.social. A pre-existing live imagePullPolicy=Never blocked +the first mail replacement; it was corrected to canonical IfNotPresent, and the +verified digest then rolled out. Source manifests preserve both corrections. + +RPF-WP-0040 is finished. Repo Manager synchronized commit +817c122d07aba02636b6deb8fe23d955d3c15e73 with equal expected/derived commit on +the primary railiance01 projection. Existing NK-WP-0033 retains the historical +resolver incident; KEY-WP-0035 and USER-WP-0030-T03 retain P06 policy/onboarding. diff --git a/tests/journey-coverage.json b/tests/journey-coverage.json index 93b8ed0..a227782 100644 --- a/tests/journey-coverage.json +++ b/tests/journey-coverage.json @@ -256,12 +256,19 @@ { "id": "P05", "role": "platform_admin", - "implementation": "external-blocked", + "implementation": "implemented", "tests": [ "test_journey_roles.PlatformAdminJourneys.test_delivery_denial_redaction_retry_and_completed_guard", - "test_platform_support.PlatformSupportJourneys.test_service_capabilities_distinguish_configuration_from_health" + "test_platform_support.PlatformSupportJourneys.test_service_capabilities_distinguish_configuration_from_health", + "test_service_operations.ServiceOperations.test_one_confirmed_delivery_and_completed_retry_guard", + "test_service_operations.ServiceOperations.test_role_csrf_and_stale_confirmation_cannot_submit", + "test_service_operations.ServiceOperations.test_failure_releases_claim_and_retry_is_available", + "test_service_operations.ServiceOperations.test_crashed_claim_reconciles_under_event_guard", + "test_service_operations.ServiceOperations.test_missing_mail_lane_never_marks_an_invitation_accepted", + "test_service_operations.ServiceOperations.test_status_is_checked_bounded_and_never_claims_receipt", + "test_service_operations.ServiceOperations.test_selected_mail_evidence_is_safe_and_read_only" ], - "remaining": "Local delivery record operations work; approved factor credential renewal and mail receipt remain external dependencies." + "remaining": "" }, { "id": "P06", diff --git a/workplans/USER-WP-0030-platform-admin-journeys.md b/workplans/USER-WP-0030-platform-admin-journeys.md index 6c48fa9..3c11939 100644 --- a/workplans/USER-WP-0030-platform-admin-journeys.md +++ b/workplans/USER-WP-0030-platform-admin-journeys.md @@ -105,3 +105,11 @@ rolled out and replacement TOTP possession confirmation is active. Evidence: docs/evidence/2026-09-13-p04-recovery.md. Positive recovery uses disposable-provider acceptance; no real user's factor was disabled. T03 remains in progress only for P05 and P06 scope; routine P04 no longer needs an OpenBao owner handoff. + + +2026-09-13 P05 completed via USER-WP-0032: checked component health, controlled +single-record delivery, durable uncertain-outcome reservations, per-event DB +serialization, provider evidence and clear assisted recovery. All source/image +CI and deployment/non-sending live checks passed. RPF-WP-0040 expiry/recovery +acceptance is finished. Evidence: docs/evidence/2026-09-13-p05-service-operations.md. +T03 now remains in progress for P06 only; notification/credential P05 is closed. diff --git a/workplans/USER-WP-0032-platform-service-operations.md b/workplans/USER-WP-0032-platform-service-operations.md index a1815f7..a4b746e 100644 --- a/workplans/USER-WP-0032-platform-service-operations.md +++ b/workplans/USER-WP-0032-platform-service-operations.md @@ -4,11 +4,12 @@ type: workplan title: "P05 checked service health and bounded delivery recovery" domain: communication repo: user-engine -status: active +status: finished owner: codex topic_slug: communication created: "2026-09-13" updated: "2026-09-13" +state_hub_workstream_id: "35af93fc-17ed-548e-8da7-616e44e8eee0" --- Complete P05 under USER-WP-0030-T03. P06 remains separate. Do not send production @@ -19,8 +20,9 @@ authentication diagnostics do not submit a message or claim inbox delivery. ```task id: USER-WP-0032-T01 -status: progress +status: done priority: high +state_hub_task_id: "0c9ebc81-ea7c-597e-a908-2806e5a8c57f" ``` Operator-only, bounded checks for KeyCape dependencies/current factor-read @@ -32,8 +34,9 @@ provider errors. Health probes must not send mail. ```task id: USER-WP-0032-T02 -status: progress +status: done priority: high +state_hub_task_id: "6be221b9-5378-54a9-ae12-37a52cc9e186" ``` Fix failed worker claims; serialize event operations across connections; confirm @@ -46,8 +49,9 @@ processing of the production backlog during this task. ```task id: USER-WP-0032-T03 -status: todo +status: done priority: high +state_hub_task_id: "5ee8bb39-e725-592e-baf2-04063c579ccd" ``` Installed-provider genuine JWT expiry, scope withdrawal/recovery and outage; @@ -55,3 +59,16 @@ native renewal/projection; SMTP/IMAP received-message and retry tests with a local mailbox; role/CSRF/stale/ambiguous-outcome browser coverage. Publish digest pinned releases and verify live non-sending status. Close RPF-WP-0040 acceptance using its specified isolated fixture rather than disrupting live authentication. + + +Completed 2026-09-13. Evidence: docs/evidence/2026-09-13-p05-service-operations.md. +227 portal tests with disposable PostgreSQL, 23 browser checks, 89 email tests, +real local SMTP/IMAP one-message retry reconciliation, installed-provider expiry / +permission recovery and native credential rotation passed. Three exact-commit +CI image releases are deployed and all six live component checks pass without +sending production mail. The invitation URL and historical Never-pull drift +are corrected in live and canonical configuration. + +Residuals already have live owners before closure: P06 is USER-WP-0030-T03 / +KEY-WP-0035; actual user inbox/acceptance journeys remain USER-WP-0028, and the +historical resolver incident remains NK-WP-0033. P05 does not claim these done.