docs: mark Phase 2 done in roadmap, capture closeout notes
This commit is contained in:
@@ -13,8 +13,9 @@ See [docs/BUILDING.md](docs/BUILDING.md).
|
||||
|
||||
## Status
|
||||
|
||||
Pre-alpha. Phases 0–1 code complete (workspace scaffold + D-Bus daemon stubs);
|
||||
Phase 2 (storage layer) is next. See [docs/plans/](docs/plans/) for design,
|
||||
roadmap, and per-phase implementation plans.
|
||||
Pre-alpha. Phases 0–2 code complete (workspace scaffold, D-Bus daemon, storage
|
||||
layer with policy.d / pending / credentials / userdb); Phase 3 (FIDO2 enrollment
|
||||
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.
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|---|---|---|---|
|
||||
| 0 | Repo, workspace, CI, packaging skeleton | 2–3 days | ✅ **Done** (2026-04-26) |
|
||||
| 1 | Daemon: D-Bus interface stub, systemd unit, polkit rules | 3–4 days | ✅ **Code complete** (2026-04-27); smoke gates deferred |
|
||||
| 2 | Daemon: storage layer (policy.d parser, pending flags, user db) | 3–4 days | **Next** — re-invoke `superpowers:writing-plans` to expand |
|
||||
| 3 | Daemon: FIDO2 enrollment backend via `ctap-hid-fido2` | 5–7 days | Spec'd |
|
||||
| 2 | Daemon: storage layer (policy.d parser, pending flags, user db) | 3–4 days | ✅ **Done** (2026-04-27, tag `v0.2.0-storage`) |
|
||||
| 3 | Daemon: FIDO2 enrollment backend via `ctap-hid-fido2` | 5–7 days | **Next** — re-invoke `superpowers:writing-plans` to expand |
|
||||
| 4 | Daemon: policy apply via pam-auth-update wrapper | 4 days | Spec'd |
|
||||
| 5 | Daemon: lockout simulator | 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).
|
||||
- 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)
|
||||
|
||||
Reference in New Issue
Block a user