test(cli): integration tests for edit/history, attachments, settings
Adds RELICARIO_TEST_ITEM_SECRET env hatch for rpassword calls in cmd_add / cmd_edit so piped-stdin tests can exercise the password prompt paths without a TTY. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -256,6 +256,16 @@ fn main() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
/// `rpassword::prompt_password` wrapper that honours `RELICARIO_TEST_ITEM_SECRET`
|
||||
/// for integration-test use (rpassword reads /dev/tty by default, which is
|
||||
/// unavailable in assert_cmd-spawned children).
|
||||
fn prompt_secret(label: &str) -> Result<String> {
|
||||
if let Ok(s) = std::env::var("RELICARIO_TEST_ITEM_SECRET") {
|
||||
return Ok(s);
|
||||
}
|
||||
rpassword::prompt_password(label).map_err(Into::into)
|
||||
}
|
||||
|
||||
fn cmd_init(image: PathBuf, output: PathBuf) -> Result<()> {
|
||||
use std::fs;
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
@@ -381,7 +391,7 @@ fn cmd_add(kind: AddKind) -> Result<()> {
|
||||
let password = if let Some(p) = password {
|
||||
Some(Zeroizing::new(p))
|
||||
} else if password_prompt {
|
||||
Some(Zeroizing::new(rpassword::prompt_password("Password: ")?))
|
||||
Some(Zeroizing::new(prompt_secret("Password: ")?))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -447,10 +457,10 @@ fn cmd_add(kind: AddKind) -> Result<()> {
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
let title = title.map(Ok).unwrap_or_else(|| prompt("Title"))?;
|
||||
let number = Zeroizing::new(rpassword::prompt_password("Card number: ")?);
|
||||
let cvv = Zeroizing::new(rpassword::prompt_password("CVV (blank to skip): ")?);
|
||||
let number = Zeroizing::new(prompt_secret("Card number: ")?);
|
||||
let cvv = Zeroizing::new(prompt_secret("CVV (blank to skip): ")?);
|
||||
let cvv = if cvv.is_empty() { None } else { Some(cvv) };
|
||||
let pin = Zeroizing::new(rpassword::prompt_password("PIN (blank to skip): ")?);
|
||||
let pin = Zeroizing::new(prompt_secret("PIN (blank to skip): ")?);
|
||||
let pin = if pin.is_empty() { None } else { Some(pin) };
|
||||
|
||||
let parsed_expiry = match expiry {
|
||||
@@ -552,7 +562,7 @@ fn cmd_add(kind: AddKind) -> Result<()> {
|
||||
let title = title.map(Ok).unwrap_or_else(|| prompt("Title"))?;
|
||||
let secret_b32 = match secret {
|
||||
Some(s) => s,
|
||||
None => rpassword::prompt_password("TOTP secret (base32): ")?,
|
||||
None => prompt_secret("TOTP secret (base32): ")?,
|
||||
};
|
||||
let secret_bytes = base32_decode_lenient(&secret_b32)?;
|
||||
let algo = match algorithm.to_ascii_lowercase().as_str() {
|
||||
@@ -862,7 +872,7 @@ fn cmd_edit(query: String) -> Result<()> {
|
||||
}
|
||||
if prompt_yesno("Change password?")? {
|
||||
let old = l.password.clone();
|
||||
let new_pw = Zeroizing::new(rpassword::prompt_password("New password: ")?);
|
||||
let new_pw = Zeroizing::new(prompt_secret("New password: ")?);
|
||||
l.password = Some(new_pw);
|
||||
if let Some(old_pw) = old {
|
||||
push_history(&mut item.field_history, "login_password",
|
||||
@@ -890,7 +900,7 @@ fn cmd_edit(query: String) -> Result<()> {
|
||||
if let Some(v) = prompt_keep_opt("Holder", c.holder.as_deref())? { c.holder = Some(v); }
|
||||
if prompt_yesno("Change card number?")? {
|
||||
let old = c.number.clone();
|
||||
c.number = Some(Zeroizing::new(rpassword::prompt_password("New number: ")?));
|
||||
c.number = Some(Zeroizing::new(prompt_secret("New number: ")?));
|
||||
if let Some(o) = old {
|
||||
push_history(&mut item.field_history, "card_number",
|
||||
Zeroizing::new(o.as_str().to_string()));
|
||||
|
||||
Reference in New Issue
Block a user