diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..ee183e4 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,104 @@ +# incredigo — project directive for Claude sessions + +**incredigo** is a local-first, encrypted, RAM-only credential custody tool (Go). +The folder is still named `credrot/`; the module/binary are `incredigo`. + +> Read this first, then [`DESIGN.md`](DESIGN.md) (architecture + threat model) and — +> if present locally — `docs/ROTATION.md` (rotation design; **gitignored**, shared +> individually, not on the upstream repo). + +## North-star goal + +A user or organization can rotate their credentials with one tool, two modes: + +- **Mode A — rotate what's already in gopass.** +- **Mode B — ingest creds first (scanners / `--path` / browser CSV), then rotate.** + +Both must run **interactively or fully headless** (`$INCREDIGO_PASSPHRASE`, no TTY): +do the automatable rotations unattended, and emit a guided worklist (+ links) for the +credentials that legitimately require a human. See `docs/ROTATION.md` Part II. + +## Where development is (2026-06-15) + +- **v1 shipped:** discover → migrate → expiry → sealed export/import. 8 scanners + (aws, env, netrc, ssh, docker, kube, git, file/`--path`); sealers age (default), + hmac, openssl. Tests green, `-race` clean. +- **Rotation: design + safety-spine only.** `internal/rotate` has the `Rotator` + interface, the **mandatory backup gate** (`Snapshot`), and a dry-run `incredigo + rotate`. **Zero rotation drivers exist; `--execute` is refused.** Nothing changes a + credential at any service yet — keep it that way until explicitly authorized. + +## Hard rules (do not violate — this tool holds real credentials) + +1. **Backup before rotate, always.** No rotation may run unless `rotate.Snapshot` + has produced a **verified** sealed backup of the affected entries first. The gate + aborts the run on any backup/verify failure. This is non-negotiable. +2. **Verify-new-before-revoke-old.** Order: backup → rotate → verify the new secret + authenticates → store in gopass → re-read → *only then* revoke the old. Never + `gopass rm` an old value before the new one is proven (SSH/DB = lockout risk). +3. **No plaintext secrets on disk. Ever.** Secrets live only in the memguard vault + and stream as bytes. Browser passwords → **worklist of non-secret metadata** + (site, username, change-URL), never a `.txt` password dump. Raw export is a + loudly-warned, flag-gated opt-in only. +4. **gopass test isolation = `GOPASS_HOMEDIR`, NOT `PASSWORD_STORE_DIR`.** gopass + ignores `PASSWORD_STORE_DIR`; `gopass init --path …` repoints the user's real + root mount and breaks their store. Always isolate tests with + `export GOPASS_HOMEDIR=$(mktemp -d)` + a throwaway `GNUPGHOME`. Better: unit-test + against a **fake gopass binary** via `sink.Gopass{Bin: …}` (see + `internal/sink/bundle_test.go`, `internal/rotate/backup_test.go`). +5. **Do no harm / self-owned only.** Browser automation targets **only the user's own + accounts**, with their authorization. Never bypass MFA/CAPTCHA — hand off to the + human. Nothing here may resemble credential stuffing or account takeover. +6. **Dry-run by default; destructive steps are opt-in, audited, reversible.** The + redacted audit log records every action. Computer-use/vision automation must + inject secrets locally and never stream them into the model loop. +7. **The PGP passphrase is the root of trust.** It unlocks every gopass secret. The + TUI and docs MUST warn prominently: lose it → everything is unrecoverable; + leak it → everything is exposed. Tell users to back up the GPG key and use a + strong passphrase. Treat this warning as a required UX element, not optional. + +## Build / test / run + +```sh +go build ./... # green required before commit +go vet ./... +go test ./... # all packages; -race clean on vault/sink/rotate +go build -o /tmp/incredigo ./cmd/incredigo +``` + +Never run `incredigo migrate/export/rotate` against the user's **real** gopass to +"test" — use an isolated `GOPASS_HOMEDIR` (rule 4). + +## Architecture + +``` +cmd/incredigo cobra CLI: scan|migrate|status|export|import|rotate +internal/vault memguard arena (mlock/DONTDUMP, zeroize, handles) +internal/discover Scanner registry + one file per source +internal/sink gopass streaming, bundle framing, Sealer (age/hmac/openssl) +internal/policy expiry engine +internal/audit redacted append-only JSONL +internal/rotate Rotator interface + MANDATORY backup gate (no drivers yet) +``` + +Extension points stay one-file-each: a Scanner, a Sealer, a Rotator. Drivers and the +backup gate live in Go; the AI router + browser long-tail belong in a skill/MCP layer +on top (do not put an LLM in the deterministic destructive hot path). + +## Chosen stack (2026 research, see ROTATION.md §13) + +- **TUI:** Charm Bubble Tea + Bubbles + Lipgloss (masked input via `textinput`). +- **Browser automation:** go-rod (default) → playwright-go (reliability) → Anthropic + Computer Use (vision fallback, secrets kept out of the loop). +- **Per-site links:** `.well-known/change-password` (RFC 8615) + a curated table. + +## Conventions + +- Match surrounding Go style; comment the *why* for any security-relevant choice. +- New code ships with tests (table-driven scanners; leak-checks asserting no secret + substring reaches `Identity`/`Meta`/logs). +- Commits: end messages with the `Co-Authored-By: Claude …` trailer. Push only when + asked. Remote is **gitea only, never GitHub** + (`https://100.117.177.50:3030/trill-technician/incredigo`). +- Design docs (`docs/ROTATION.md`) are kept local/gitignored by request; `DESIGN.md`, + `README.md`, `docs/SECURITY.md`, `docs/ADDING_A_SCANNER.md` are tracked.