SecondBrain/credvault-gem-plan.md

85 lines
4.3 KiB
Markdown
Raw Normal View History

2026-07-09 21:22:28 +00:00
---
type: plan
title: "credvault Ruby gem — implementation plan"
summary: Implementation plan for the credvault Ruby gem wrapping the bw CLI with ensure/get/rotate/list/status operations, Sandi Metz ports-and-adapters design, sync-before-read, global locking, and a Minitest strategy.
tags:
- type/plan
- project/credvault
- tool/vaultwarden
- domain/credential-management
- domain/ruby
scope: project
date: 2026-07-09
last_updated: 2026-07-09
related:
- credvault-integration-master-plan
- credvault-vaultwarden-setup-plan
source: ruby-gems
---
# credvault Gem — Implementation Plan
Home: `~/dev/ruby-gems/credvault/` (private GitHub repo, use git-context:repo-init).
Follows the planka-api sibling pattern: client layer + CLI, Minitest, small objects.
## Surface (frozen)
Commands: `ensure`, `get`, `rotate`, `list`, `status`. **No delete, no export, no raw bw
passthrough.** JSON output, stable error codes (`authentication_failed`, `vault_locked`,
`collection_unavailable`, `credential_not_found`, `duplicate_managed_key`, `invalid_key`,
`invalid_password_policy`, `bitwarden_command_failed`, `configuration_error`).
Org/collection IDs come from `~/.config/credvault/config.yml` only — never CLI args.
## Object model (ports and adapters)
```
CredentialKey, Credential, PasswordPolicy # domain values
Operations::{Ensure,Get,Rotate,List}Credential(s) # use cases, depend on Vault::Repository
Vault::Repository (interface) ← Vault::BitwardenRepository
Bitwarden::{Client, Session, ProcessRunner} # adapter; Open3.capture3 argv arrays only
Presenters::JsonPresenter
exe/credvault
```
## Non-negotiable behaviors (from critique)
1. **`bw sync` before every read path** (ensure/get/rotate/list) — stale local cache
otherwise breaks idempotency and creates duplicates.
2. **One global file lock serializes ALL bw invocations** (shared appdata dir is unsafe for
concurrent bw processes), not just find-then-create.
3. **Custom-field lookup is client-side**: list collection items, parse JSON, filter on
`managed_key` custom field (`bw list --search` doesn't cover custom fields).
4. **Duplicate `managed_key` → explicit error**, never arbitrary pick. Cross-host races are
detected-and-reported, not prevented.
5. **Auth lifecycle fully owned**: login-state persisted in `BITWARDENCLI_APPDATA_DIR`;
`unlock --passwordfile` per invocation; `lock` on exit; BW_SESSION only in process memory,
never in logs/errors/output. Master-password file is mode-600 (owned by the invoking user;
OS isolation is a future hardening option, not v1).
6. **Rotation is vault-only and says so**: output must remind the caller that the live app
still holds the old secret (two-phase workflow is the caller's job). v1 may refuse rotation
without `--acknowledge-live-impact` style flag.
7. **Audit log** (JSONL, `~/.local/state/credvault/audit.jsonl`): timestamp, operation, key,
result, item_id. Every `get` is logged. Never any secret material.
8. Password generation via `bw generate` or Ruby SecureRandom under named policies
(`strong` 32 full-charset default, `compatibility` no-special, `passphrase` 5 words).
## Testing (Minitest)
- **Unit**: fake Vault::Repository — ensure returns existing / creates missing / rejects
duplicates; rotate fails on missing key and preserves metadata; list excludes secrets;
no auth material in any output/error.
- **Adapter**: fake ProcessRunner with canned bw JSON (login, unlock, sync, list, create,
edit, lock) — primary seam, matches planka-api pattern.
- **High-fidelity**: a fake `bw` shell script on PATH to exercise real Open3/argv/exit codes.
- **Integration** (optional, tagged): disposable Vaultwarden container. Never production.
## Build order & delegation
1. Skeleton + config + error model + ProcessRunner/Client/Session (`status` end-to-end) — one
sonnet agent. Blocker for the rest: defines the interfaces.
2. **In parallel** (disjoint operations against slice-1 interfaces, merged before review):
- `get` + `list` (read paths, sync + lock + client-side filter) — sonnet.
- `ensure` + `rotate` + audit log + policies — sonnet.
3. Security/quality pass — opus review + /code-review before first production use.
Each slice ships with its tests green; design decisions are all above, so agents don't improvise.