test(cli): integration harness + basic flow tests

Uses assert_cmd + tempfile to spin up a fresh vault per test.
Covers init layout, add/list/get mask semantics, rm/restore/purge cycle,
and generate smoke. Adds RELICARIO_TEST_PASSPHRASE env-var hatch in
unlock_interactive and cmd_init so tests don't need a TTY.

Also fixes read_params in session.rs to correctly parse the nested
params.json format (kdf sub-object) rather than trying to deserialize
the whole file as KdfParams.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-04-20 18:32:45 -04:00
parent 494eedbbb8
commit b263c27da9
6 changed files with 741 additions and 42 deletions

View File

@@ -272,8 +272,18 @@ fn cmd_init(image: PathBuf, output: PathBuf) -> Result<()> {
}
// Passphrase with strength gate (audit H3).
let passphrase = Zeroizing::new(rpassword::prompt_password("Choose a passphrase: ")?);
let confirm = Zeroizing::new(rpassword::prompt_password("Confirm passphrase: ")?);
// RELICARIO_TEST_PASSPHRASE is a test-only escape hatch that bypasses the
// TTY prompt so integration tests can run without a real TTY.
let passphrase = if let Ok(p) = std::env::var("RELICARIO_TEST_PASSPHRASE") {
Zeroizing::new(p)
} else {
Zeroizing::new(rpassword::prompt_password("Choose a passphrase: ")?)
};
let confirm = if std::env::var_os("RELICARIO_TEST_PASSPHRASE").is_some() {
passphrase.clone()
} else {
Zeroizing::new(rpassword::prompt_password("Confirm passphrase: ")?)
};
if passphrase.as_str() != confirm.as_str() {
anyhow::bail!("passphrases do not match");
}