pwstore: pass/gopass + macOS Keychain in-place adapters

Group 2 of the manager wire-up — two CLI ItemUpdaters:

  pass/gopass: the user's own password-store as a rotation source. Reads
  line-1=password + key:value metadata via `<bin> show`; updates in place by
  piping the full body to `<bin> insert -m -f` (off-argv), preserving metadata
  across the password swap. gopass enumerates via `ls --flat`, pass by walking
  the store dir; --pass-prefix scopes a subtree.

  keychain: macOS internet passwords via the `security` CLI. Pure-exec (no
  build tag) so it unit-tests cross-platform via a fake bin; Available() is
  false off darwin. Read off-argv (find-internet-password -w); write is
  delete+add with -w on argv (CLI limitation, documented like 1password).

Both MOCK-ONLY (fake-binary unit tests + leak checks); recorded as DATA in
BROWSER-ROTATION.md §8. 153 tests green, vet clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
leetcrypt
2026-06-20 11:39:20 -07:00
parent 4f5939a3e3
commit 851890b119
6 changed files with 796 additions and 3 deletions
+17
View File
@@ -235,6 +235,11 @@ via real registration crypto). **keepassxc is LIVE-VM** — proven end to end ag
`lab-provision-browsercsv.sh`; only the final human re-import is unproven (see note ²). All in
the `incredigo-sbx` sandbox VM.
Three more **in-place CLI adapters** are **MOCK-ONLY** (unit-validated via injected fake
binaries; no LIVE-VM POC yet): **pass / gopass** (the user's own password-store as a rotation
source — off-argv write, full body piped to `<bin> insert -m -f`, metadata preserved across the
swap), and **keychain** (macOS `security` CLI — darwin-only at runtime, argv write caveat ³).
The **CSV-manager family** (edge/brave/safari/lastpass/dashlane/protonpass/nordpass/roboform/
enpass) shares the chrome/firefox staging machinery via one generic `csvManager`, so its
security-critical path (tmpfs + correct per-manager import layout + shred, `--allow-csv` gated)
@@ -249,6 +254,8 @@ headers — there is no LIVE-VM round-trip into the actual managers yet. `enpass
| bitwarden | `bw edit item` (stdin) | **yes** — base64 on stdin | **real bw 2026.5.0 + Vaultwarden 1.36 (LIVE-VM)** |
| keepassxc | `keepassxc-cli edit -p`| **yes** — db+new pass on stdin | **real keepassxc-cli 2.7.6 (LIVE-VM)** |
| 1password | `op item edit pw=…` | **no** — argv assignment¹ | fake `op` (MOCK-ONLY) |
| pass / gopass | `<bin> insert -m -f` (stdin) | **yes** — full body on stdin | fake `pass`/`gopass` bin (MOCK-ONLY) |
| keychain | `security add-internet-password -w` | **no** — argv assignment³ | fake `security` bin (MOCK-ONLY) |
| chrome | tmpfs CSV → human re-import | n/a (no live secret to a child) | **real /dev/shm + shred (LIVE-VM²)** |
| firefox | tmpfs CSV → human re-import | n/a | **real /dev/shm + shred (LIVE-VM²)** |
| edge / brave | tmpfs CSV (chrome layout) → re-import | n/a | shared staging code (LIVE-VM²); layout MOCK-ONLY (unit) |
@@ -286,6 +293,16 @@ than the Bitwarden/KeePassXC stdin paths; it is in-RAM, transient, and never tou
choice is documented here rather than hidden in the driver. Promoting any adapter to a
real-binary proof level requires a sandbox-VM POC against the genuine CLI / browser import.
³ **Keychain argv caveat:** the macOS `security` CLI has no in-place edit and no stdin path
for writing — `add-internet-password -w <new>` takes the secret on argv, so it is briefly
visible to **same-uid** processes via `ps`/`/proc`-equivalent, exactly like the 1Password
caveat (¹). The read side stays off argv (`find-internet-password -w` prints to stdout into the
vault). Update is delete-then-add (no atomic replace). Bulk export is also inherently
prompt-heavy on a real Mac (`find-internet-password -w` triggers a keychain-access prompt per
item unless the ACL already trusts the caller); incredigo skips items it cannot read rather than
aborting. Keychain is **darwin-only at runtime**`Available()` is false off macOS — but the
adapter is pure-exec Go, so it is unit-validated cross-platform via an injected fake `security`.
## 9. Roadmap
- **Phase B (now):** `pwgen` + `pwstore` (interface + Bitwarden/1Password/KeePassXC in-place +