Skip to main content

envvault/cli/commands/
set.rs

1//! `envvault set` — add or update a secret in the vault.
2
3use 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
10/// Execute the `set` command.
11pub fn execute(cli: &Cli, key: &str, value: Option<&str>, force: bool) -> Result<()> {
12    let path = vault_path(cli)?;
13
14    // Determine the secret value from one of three sources.
15    let secret_value = if let Some(v) = value {
16        // Source 1: Inline value on the command line.
17        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        // Source 2: Piped input (stdin is not a terminal).
23        let mut buf = String::new();
24        io::stdin().read_to_string(&mut buf)?;
25        buf.trim_end().to_string()
26    } else {
27        // Source 3: Interactive secure prompt (default).
28        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    // Open the vault, set the secret, and save.
37    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}