envvault/cli/commands/
set.rs1use std::io::{self, IsTerminal, Read};
4
5use crate::cli::output;
6use crate::cli::{load_keyfile, prompt_password_for_vault, vault_path, Cli};
7use crate::errors::Result;
8use crate::vault::VaultStore;
9
10pub fn execute(cli: &Cli, key: &str, value: Option<&str>) -> Result<()> {
12 let path = vault_path(cli)?;
13
14 let secret_value = if let Some(v) = value {
16 output::warning("Value provided on command line — it may appear in shell history.");
18 v.to_string()
19 } else if !io::stdin().is_terminal() {
20 let mut buf = String::new();
22 io::stdin().read_to_string(&mut buf)?;
23 buf.trim_end().to_string()
24 } else {
25 dialoguer::Password::new()
27 .with_prompt(format!("Enter value for {key}"))
28 .interact()
29 .map_err(|e| {
30 crate::errors::EnvVaultError::CommandFailed(format!("input prompt: {e}"))
31 })?
32 };
33
34 let keyfile = load_keyfile(cli)?;
36 let vault_id = path.to_string_lossy();
37 let password = prompt_password_for_vault(Some(&vault_id))?;
38 let mut store = VaultStore::open(&path, password.as_bytes(), keyfile.as_deref())?;
39
40 let existed = store.get_secret(key).is_ok();
41 store.set_secret(key, &secret_value)?;
42 store.save()?;
43
44 let op_detail = if existed { "updated" } else { "added" };
45 crate::audit::log_audit(cli, "set", Some(key), Some(op_detail));
46
47 if existed {
48 output::success(&format!(
49 "Secret '{}' updated in {}.vault ({} total)",
50 key,
51 cli.env,
52 store.secret_count()
53 ));
54 } else {
55 output::success(&format!(
56 "Secret '{}' added to {}.vault ({} total)",
57 key,
58 cli.env,
59 store.secret_count()
60 ));
61 }
62
63 output::tip("Run your app: envvault run -- <command>");
64
65 Ok(())
66}