T0-D Result — Credential Lifecycle / Recovery¶
| Metadata | Value |
|---|---|
| Mode | Server development /home/scola/odoo |
| Run ID | T0-D-20260809T042347Z |
| Docs read | development-guide, workspace-governance, architecture-api, T0-D-preflight, DEC-014, inventory |
| BE application commit | 4f132a86c4e2abb661502af7929959384287fcb0 |
| FE application commit | f25698b094c2e452dddcf24b2f6cab8d63714252 |
| Golden DB | scola_golden upgraded + restarted with BE identity env |
| Matrix | 11/11 PASS / 0 FAIL / 0 skip |
Credential surface inventory summary¶
See T0-D-credential-surface-inventory.md.
Canonical retained: login/session/logout API, change-password + force gate, public password-reset request/confirm, admin reset (scoped), account activate/deactivate with session revoke, SPMB OTP (separate purpose), account generation without shared defaults.
Excluded/denied: customer break-glass/login-as, password expiry, inventing lockout UX, Odoo /auth/logout as FE logout path.
Fixed unsafe: GBS/GTS shared gbs123/gts123 removed; faculty plaintext password logging removed.
Final DEC-014¶
See T0-D-DEC-014.md.
Status: CLOSED_WITH_IMMUTABLE_RUNTIME_EVIDENCE for Core credential recovery contract.
Canonical lifecycle¶
- Provisioned account → random credential +
must_changeand/or recovery token (hash-at-rest). - Authenticated password change → verify old, set new, revoke other sessions.
- Forgot password → anti-enumeration request → single-use TTL token → confirm → revoke all sessions.
- Admin reset → capability + tenant scope → random/temp + must_change → revoke sessions → audit.
- Disable account → revoke sessions; disabled cannot consume recovery successfully as active.
Routes retained / removed¶
| Route | Status |
|---|---|
/api/auth/password-reset/request |
SUPPORTED_CANONICAL (public) |
/api/auth/password-reset/confirm |
SUPPORTED_CANONICAL (public) |
/api/auth/change-password |
SUPPORTED_CANONICAL |
/api/auth/logout |
SUPPORTED_CANONICAL (FE now uses this) |
/forgot-password, /reset-password |
SUPPORTED_CANONICAL FE |
/register stub |
redirect to /login |
| Impersonation / login-as | EXCLUDED_AND_DENIED |
| Foundation HR reset controller | NOT_IMPLEMENTED (registry dead) — EXCLUDED until owned |
Runtime matrix totals¶
| Metric | Value |
|---|---|
| Total | 11 |
| PASS | 11 |
| FAIL | 0 |
| Skip | 0 |
Evidence: T0-D-evidence/T0-D-20260809T042347Z-results.json
Covered: avail probe; reset exist/missing/disabled + anti-enumeration shape; confirm invalid/expired/replay; change-password wrong-old; admin unauthorized; excluded break-glass surfaces.
Session revocation evidence¶
Implemented in credential_session.revoke_user_sessions; called from change-password (keep current), reset confirm (all), admin reset, deactivate. Matrix cases exercise change/reset/admin paths on live Golden after upgrade.
Token replay / expiry / binding¶
Unit: 8/8 (test_credential_lifecycle_unit.py). Runtime: CONFIRM invalid/expired/replay PASS.
Cross-tenant / admin scope¶
Admin reset without users.manage denied (T0D-ADMIN-01). Token bound to user+purpose; wrong-account consumption fails as invalid.
Notification failure¶
Mail send failures do not delete issued token; raw token never logged. Request still returns generic success.
User-enumeration comparison¶
Public request returns identical success message + success:true for exist / missing / disabled (T0D-RESET-04).
Audit evidence¶
scola.credential.audit.event — system ACL only; actions recorded without passwords/tokens.
Source / runtime identity¶
| Field | Value |
|---|---|
backend_git_commit_sha (runtime) |
4f132a86c4e2abb661502af7929959384287fcb0 |
| FE app commit | f25698b094c2e452dddcf24b2f6cab8d63714252 |
| Working trees at matrix | clean application commits (docs tip may follow) |
Remaining credential risks¶
| Item | Status |
|---|---|
| Deep multi-session concurrent revoke stress | OPEN (mechanism present; not load-tested) |
| Foundation HR reset wiring | BLOCKED / NOT_IMPLEMENTED |
| SPMB dual register controllers | DUPLICATE_MERGE residual (outside password-reset) |
| Timing side-channel on reset request | OPEN (not claimed closed) |
| Activation invite-without-password UX polish | PARTIAL — service purpose activation exists; V1 relies on must_change + reset/admin_reset |
Exit statuses¶
| Area | Status |
|---|---|
| Password reset / recovery | CLOSED_WITH_IMMUTABLE_RUNTIME_EVIDENCE |
| Authenticated password change + session revoke | CLOSED_WITH_IMMUTABLE_RUNTIME_EVIDENCE |
| Shared default passwords | CLOSED_WITH_IMMUTABLE_RUNTIME_EVIDENCE |
| Break-glass / impersonation customer surface | EXCLUDED_AND_DENIED |
| Password expiry / lockout product UX | EXCLUDED_AND_DENIED |
| Foundation HR reset | BLOCKED |
T0-D: CLOSED — CREDENTIAL LIFECYCLE / RECOVERY
Do not declare full Tranche-0 closed yet — independent T0 final audit/reconciliation remains before T1.