docs: mark Phase 2 done in roadmap, capture closeout notes

This commit is contained in:
michael
2026-04-27 06:45:11 -07:00
parent 24237cbf8b
commit f655d41f5c
2 changed files with 27 additions and 5 deletions

View File

@@ -13,8 +13,9 @@ See [docs/BUILDING.md](docs/BUILDING.md).
## Status ## Status
Pre-alpha. Phases 01 code complete (workspace scaffold + D-Bus daemon stubs); Pre-alpha. Phases 02 code complete (workspace scaffold, D-Bus daemon, storage
Phase 2 (storage layer) is next. See [docs/plans/](docs/plans/) for design, layer with policy.d / pending / credentials / userdb); Phase 3 (FIDO2 enrollment
roadmap, and per-phase implementation plans. backend) is next. See [docs/plans/](docs/plans/) for design, roadmap, and
per-phase implementation plans.
Copyright 2026 Dangerous Things, LLC. Licensed under the Apache License, Version 2.0. Copyright 2026 Dangerous Things, LLC. Licensed under the Apache License, Version 2.0.

View File

@@ -20,8 +20,8 @@
|---|---|---|---| |---|---|---|---|
| 0 | Repo, workspace, CI, packaging skeleton | 23 days | ✅ **Done** (2026-04-26) | | 0 | Repo, workspace, CI, packaging skeleton | 23 days | ✅ **Done** (2026-04-26) |
| 1 | Daemon: D-Bus interface stub, systemd unit, polkit rules | 34 days | ✅ **Code complete** (2026-04-27); smoke gates deferred | | 1 | Daemon: D-Bus interface stub, systemd unit, polkit rules | 34 days | ✅ **Code complete** (2026-04-27); smoke gates deferred |
| 2 | Daemon: storage layer (policy.d parser, pending flags, user db) | 34 days | **Next** — re-invoke `superpowers:writing-plans` to expand | | 2 | Daemon: storage layer (policy.d parser, pending flags, user db) | 34 days | **Done** (2026-04-27, tag `v0.2.0-storage`) |
| 3 | Daemon: FIDO2 enrollment backend via `ctap-hid-fido2` | 57 days | Spec'd | | 3 | Daemon: FIDO2 enrollment backend via `ctap-hid-fido2` | 57 days | **Next** — re-invoke `superpowers:writing-plans` to expand |
| 4 | Daemon: policy apply via pam-auth-update wrapper | 4 days | Spec'd | | 4 | Daemon: policy apply via pam-auth-update wrapper | 4 days | Spec'd |
| 5 | Daemon: lockout simulator | 3 days | Spec'd | | 5 | Daemon: lockout simulator | 3 days | Spec'd |
| 6 | PAM module: `pam_authforge_pending.so` (C) | 3 days | Spec'd | | 6 | PAM module: `pam_authforge_pending.so` (C) | 3 days | Spec'd |
@@ -66,6 +66,27 @@ Phase 1 expanded to step granularity at [2026-04-26-phase-1-dbus.md](2026-04-26-
- `PendingFlag.deadline_unix` is `u64` with `0` = no deadline (zvariant `Type` derive does not support `Option<T>`; sentinel matches the design doc's existing `deadline_hours = 0` convention). - `PendingFlag.deadline_unix` is `u64` with `0` = no deadline (zvariant `Type` derive does not support `Option<T>`; sentinel matches the design doc's existing `deadline_hours = 0` convention).
- Sender → pid resolution for polkit `unix-process` subjects punts to early Phase 2 — Phase 1 passes pid 0, which the permissive authorizer ignores. Until pid resolution lands, the daemon is run with `AUTHFORGE_POLKIT_BYPASS=1` for any local smoke test (loud `warn!` log on startup). - Sender → pid resolution for polkit `unix-process` subjects punts to early Phase 2 — Phase 1 passes pid 0, which the permissive authorizer ignores. Until pid resolution lands, the daemon is run with `AUTHFORGE_POLKIT_BYPASS=1` for any local smoke test (loud `warn!` log on startup).
### Phase 2 closeout notes (2026-04-27)
Phase 2 expanded to step granularity at [2026-04-27-phase-2-storage.md](2026-04-27-phase-2-storage.md). All 17 tasks landed in 8 commits, tagged `v0.2.0-storage`.
**Done in Phase 2:**
- `common/src/policy.rs``Policy::load_from_dir` (lex-ordered last-wins merge; ignores non-`.conf`; missing-dir → default) and `Policy::save_local` (writes `50-local.conf`, never touches siblings). Policy-related types moved here from `types.rs` with re-exports for stability.
- `daemon/src/storage/policy.rs``PolicyStore` wraps load/save; `watch()` returns a `(RecommendedWatcher, watch::Receiver<()>)` driven by `notify::recommended_watcher` (inotify on Linux).
- `daemon/src/storage/pending.rs` — JSON read/write/clear with explicit path-traversal rejection (`.`, `..`, `/`, `\0`, empty).
- `daemon/src/storage/credentials.rs``pam_u2f` line parser (`username:cred1[:cred2…]`), `CredentialsStore` with idempotent add-by-credId and remove-by-credId, `CredsPathResolver` dispatching central vs per-user paths (NSS errors fall back to `/home/<user>/…`).
- `daemon/src/storage/userdb.rs``rusqlite` (bundled SQLite) cache for the lockout simulator; `record_enrollment`, `drop_enrollment`, `users_with`, `has_any`.
- `daemon/src/dbus.rs` — adds `#[zbus(signal)] policy_changed`. Tests run against tempdir-backed `AppState` seeded with central-mode storage so credential writes don't try to touch `/home/<user>/…`.
- `daemon/src/main.rs` — spawns a watcher task that emits `PolicyChanged` on every `rx.changed()`; `AUTHFORGE_POLICY_DIR`/`_PENDING_DIR`/`_USERDB` env-var overrides for non-prod runs.
- `AppState::open(StorageConfig)` replaces `with_fixtures()`. All storage errors threaded through `StateError` and surfaced as `org.freedesktop.DBus.Error.Failed`.
**Test count:** 13/13 common + 26/26 daemon = **39 tests** (was 14+7=21 at end of Phase 1). Clippy + fmt clean.
**Plan deviations:**
- `nix::unistd::User::from_name` returns `Err(ENOENT)` rather than `Ok(None)` on this dev box for unknown users; the resolver now treats any lookup error as "fall back to `/home/<user>`" rather than propagating. Comment updated.
- `set_policy_replaces_state` test renamed to `set_policy_persists_stacks` and asserts only `merged.stacks == pol.stacks``p2p_pair` seeds a `[storage]` block in `00-test.conf`, so the merged read is by design a superset of what `SetPolicy` wrote to `50-local.conf`. The new assertion captures the actual user-visible behavior.
- `.gitignore` extended to ignore `.claude/` (Phase 1 left a stale agent worktree under `.claude/worktrees/`; ignoring prevents accidental submodule-style commits).
--- ---
# Phase 0: Repository Scaffolding (FULLY DETAILED) # Phase 0: Repository Scaffolding (FULLY DETAILED)