Skip to content

Latest commit

 

History

History
108 lines (84 loc) · 6.51 KB

File metadata and controls

108 lines (84 loc) · 6.51 KB

AGENTS.md — rpass

CLI password manager (Rust). Optimize for short context: read this first, then only the files you need.

Stack

  • Rust edition 2021, package rpass (src/lib.rs + bin src/main.rs)
  • CLI: clap derive · crypto: argon2 + aes-gcm + rand · secrets wipe: zeroize
  • Errors: thiserror (error::Error / error::Result) — avoid bare unwrap in lib paths
  • Serde JSON vault file · config TOML · storage under XDG dirs

Layout (where to edit)

Path Responsibility Touch when…
src/cli/mod.rs dispatch run() wire new commands
src/cli/args.rs clap structs / enums flags, subcommands
src/cli/handlers.rs cmd_* handlers command behaviour
src/cli/prompt.rs master-password prompts, open_vault UX prompts
src/cli/clipboard.rs clipboard copy / clear clipboard UX
src/cli/repl.rs interactive mode REPL commands
src/vault.rs unlocked vault API, CRUD, audit, import/export, tables business ops on entries
src/crypto.rs KDF, AES-GCM, password gen, TOTP, strength, HIBP, b64 crypto behaviour
src/wordlist.txt passphrase dictionary Diceware words
src/storage.rs FileStore, seal/unseal, session, backups, paths persistence / session / paths
src/models.rs Entry, VaultData, MasterKey, audit types data shape / serde fields
src/config.rs TOML config + env + VaultPrefs defaults, keys, multi-vault map
src/error.rs error enum (Display via i18n) new failure modes
src/i18n.rs EN/FR UI language (t / tfmt! / init) new UI strings
src/main.rs parse → cli::run, exit codes exit mapping only
tests/vault_flow.rs library lifecycle tests vault API regressions
tests/integration.rs binary smoke tests CLI surface smoke
completions/* shell completion scripts new top-level commands

Do not invent parallel storage layers. Extend VaultStore / FileStore if needed.

Design invariants (do not break)

  1. Disk always encrypted: plaintext VaultData exists only in memory after unlock. Mutate → Vault::save()storage::seal (AES-GCM, fresh nonce each write).
  2. File format EncryptedVault: version, salt (b64), nonce (b64), ciphertext (b64+tag), written_at. Atomic write: *.tmp + rename; Unix mode 0600.
  3. Key hierarchy: master password + salt → Argon2id (hash_password_into) → 32-byte MasterKey (zeroized). Session (P0): master key scellée dans data_dir/.{name}.session ; wrap key dans runtime_dir/{name}.wrap ($RPASS_RUNTIME_DIR ou $XDG_RUNTIME_DIR/rpass, sinon data_dir/runtime/). Jamais les deux dans le même fichier. vault_path validé ; is_session_active ne déchiffre pas / ne prolonge pas.
  4. Decrypt errors: crypto::decryptDecryptFailed ; storage::unseal (MDP saisi) mappe vers WrongMasterPassword. Session invalide → purge + VaultLocked.
  5. Write lock: FileStore::save_encrypted prend un lock coopératif {name}.vault.lock (PID) ; erreur VaultBusy si concurrent vivant.
  6. Entry keys in map: lowercase service name (VaultData::entry_key). Display name keeps original casing.
  7. Password change goes through Entry::set_password (history, max 10, updates password_changed_at).
  8. Unlock: Vault::open_or_prompt / session first — do not require password if session valid.
  9. Clipboard: effacement non garanti en CLI one-shot ; RPASS_CLIPBOARD_WAIT=1 force l'attente. REPL OK.
  10. No exploit PoCs, no weak crypto “for tests” in production paths. Tests may use temp dirs via RPASS_DATA_DIR / RPASS_CONFIG / RPASS_RUNTIME_DIR.

Default paths

  • Vault: $RPASS_DATA_DIR or dirs::data_dir()/rpass/{name}.vault → typically ~/.local/share/rpass/default.vault
  • Config: $RPASS_CONFIG or ~/.config/rpass/config.toml
  • Session meta: data dir .{name}.session
  • Session wrap key: runtime dir {name}.wrap
  • Backups: data dir backups/{name}_{timestamp}.vault.bak
  • Env overrides: RPASS_VAULT, RPASS_VAULT_PATH, RPASS_DATA_DIR, RPASS_RUNTIME_DIR, RPASS_TIMEOUT, RPASS_PASSWORD_LENGTH, RPASS_LANG (en/fr), RPASS_CLIPBOARD_WAIT, NO_COLOR

Commands map (CLI ↔ logic)

  • Vault mgmt: init|unlock|lock|change-master-password|status|destroyVault::* + session in storage
  • CRUD: add|get|show|list|update|delete|searchVault + vault::print_*
  • Gen: generate / auto on addcrypto::generate_password / vault::gen_password_from_opts
  • Audit: audit|check-breach|strength|expireVault::audit, crypto::{check_breach,password_strength}
  • TOTP: add-totp|totpVault::{add_totp,totp} / crypto::generate_totp*
  • I/O: export|import|backup|restore → vault import/export helpers + storage::{create_backup,restore_backup}
  • Config/REPL/completions: config|*, interactive, completions

Global flag: --vault <name> (not short -V; version uses -V).

Conventions

  • Errors: add variants in error.rs, return Result<T>, map at boundaries in cli.rs.
  • UI strings: English default; French via RPASS_LANG=fr / config.language using crate::i18n::{t,tfmt,init}.
  • Display tables: colored / comfy-table; respect password masking unless --show.
  • Clipboard: best-effort (arboard); failure must not abort core ops.
  • Sensitive types: MasterKey, MasterPassword use Zeroize/ZeroizeOnDrop — keep secrets out of Debug logs.
  • Prefer small functions; keep clap structs and handlers in cli.rs (large file — jump via command name / fn cmd_).
  • Imports: std → external → crate::.

Verify before done

cargo test
cargo build          # or --release for CLI smoke
./target/debug/rpass --help

Targeted:

cargo test --test vault_flow
cargo test --lib crypto

Need isolated vault in tests: set RPASS_DATA_DIR + RPASS_CONFIG to a temp dir (see tests/vault_flow.rs).

Out of scope (unless asked)

Multi-user/sync-cloud, team hybrid crypto, full i18n, generated man pages, clap_complete crate (completions are static under completions/).

Token hygiene for agents

  • Prefer surgical reads of one module; for CLI: args.rs (flags) → handlers.rs (fn cmd_) → repl.rs if REPL.
  • After behavior change in vault/crypto/storage: update or add a test in tests/vault_flow.rs or unit tests in the same module.
  • Do not re-document the whole README in PRs; change README only if user-facing paths/commands change.
  • Avoid drive-by refactors and new heavy deps without need.