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