diff --git a/docs/plans/2026-04-26-authforge-implementation.md b/docs/plans/2026-04-26-authforge-implementation.md index fd0719f..d5070d5 100644 --- a/docs/plans/2026-04-26-authforge-implementation.md +++ b/docs/plans/2026-04-26-authforge-implementation.md @@ -39,7 +39,7 @@ | 9 | GUI: Policy tab + lockout-warning UX | 4 days | **Spec'd** — opens after Phase 8 | | 10 | First-login flow: autostart entry + fullscreen modal | 4 days | **Spec'd** — needs Phase 6 ✓ + Phase 8 | | 11 | TOTP support (PAM module + GUI tab) — feature flag | 5 days | **Spec'd** — opens now (needs Phase 2 ✓ + Phase 4 ✓) | -| 12 | Recovery flow (codes + emergency unlock) | 4 days | **Spec'd** — opens now (needs Phase 6 ✓) | +| 12 | Recovery flow (codes + emergency unlock) | 4 days | ✅ **Code complete** (2026-04-27) — backend + PAM landed; GUI tab queued in Phase 9 lane | | 13 | Debian packaging finalization (postinst, debconf, purge) | 4 days | **Spec'd** — sequential tail; needs all binaries built | | 14 | Launchpad PPA build setup | 2 days | **Spec'd** — sequential tail after 13; **VM smoke gate for all "Code complete" phases** | | 15 | `authforge-gnome-integration` (Users panel shortcut) | 3 days | ✅ **Done** (2026-04-27) — parallel subagent (gnome lane) | @@ -48,7 +48,7 @@ | 18 | User docs + onboarding site | 3 days | **Spec'd** — anytime slot | | **R** | **v1.0 release** | 1 day | — | -**Progress: 11 of 19 phases code-complete (58%).** Total original estimate was ~14 weeks of focused work for v1.0. Subsequent phases (Debian packaging, KDE port, RPM) are scoped in the design doc. +**Progress: 12 of 19 phases code-complete (63%).** Total original estimate was ~14 weeks of focused work for v1.0. Subsequent phases (Debian packaging, KDE port, RPM) are scoped in the design doc. --- @@ -230,6 +230,29 @@ Both delivered by parallel subagents in `git worktree` isolation while Lane 1 (P - All 5 YAML files validated via `yaml.safe_load`. `ansible-lint` skipped — not installed in the harness sandbox. - **Subagent-initiated divergences (kept):** added `authforge_ppa` override variable so internal-mirror users don't fork the role; pre-creates `/etc/authforge/policy.d/` defensively (idempotent); standard `ansible_managed` template header. +### Phase 12 backend closeout notes (2026-04-27) + +Backend + PAM landed via the plan at [2026-04-27-phase-12-recovery-backend.md](2026-04-27-phase-12-recovery-backend.md). 9 commits on `feature/phase-12-recovery-backend`. GUI tab is queued in the Phase 9 lane (waiting on Phase 8). + +**Done:** +- `daemon/src/storage/safe_user.rs` — extracted shared username path-segment sanitizer; `PendingStore` migrated to it. 2 new unit tests. +- `daemon/src/recovery.rs` — pure logic: `generate_code` (8 digits), `hash_code` (Argon2id PHC via OS RNG salt), `verify_code` (constant-time). 4 unit tests. +- `daemon/src/storage/recovery.rs` — `RecoveryStore`: atomic 0600 writes (temp+rename), two-line file format `\n\n`, one-shot `verify_and_consume` semantics, expiry handling, alphabetical `list()`. 7 unit tests. +- `StorageConfig` gains `recovery_dir` field with `AUTHFORGE_RECOVERY_DIR` env override (default `/var/lib/authforge/recovery`). `AppState` exposes `issue_recovery` / `list_recovery` / `revoke_recovery`. +- D-Bus: real `GenerateRecoveryCode` (replaced stub), new `ListRecoveryCodes` (returns `Vec`), new `RevokeRecoveryCode`. polkit policy gains `…list-recovery` + `…revoke-recovery` actions (`auth_admin_keep`). 4 new D-Bus integration tests including a real on-disk `$argon2id$` PHC round-trip. +- PAM module gains a `mode=recovery` argv branch. Reads the two-line file, `argon2_verify`s against `PAM_AUTHTOK`; on match unlinks the recovery file (one-shot) and writes `pending(re_enroll=true)`. Always returns `PAM_IGNORE` on failure paths so a missing/wrong code never blocks normal auth. Linked against `libargon2`. +- `policy_apply::render_profile` renders the recovery line first in the auth stack with `[success=done default=ignore]` so a successful recovery short-circuits the rest of the auth chain. +- CLI: `authforgectl recovery list` (was placeholder) and `authforgectl recovery revoke `. List takes no args (matches D-Bus signature). + +**Test count:** 7 cli + 13 common + 60 daemon = **80 tests** (was 5+13+42=60 at end of Phase 4+5). +20 tests across the 7 implementation tasks. + +**Plan deviations:** none of substance. + +**Deferred until Phase 14 VM smoke:** +- `make -C pam` against a host with `libargon2-dev` installed (not in the dev sandbox). +- `pamtester` recovery walkthrough — recipe lives in `pam/TESTING.md` § Smoke test 4. +- End-to-end recovery flow against a real PAM stack: admin issues code via CLI → user logs in entering it at the password prompt → recovery file deleted → pending(re_enroll=true) flag present → re-enrollment modal triggers on next login. + --- # Phase 0: Repository Scaffolding (FULLY DETAILED)