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>) -> 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        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        // Source 2: Piped input (stdin is not a terminal).
21        let mut buf = String::new();
22        io::stdin().read_to_string(&mut buf)?;
23        buf.trim_end().to_string()
24    } else {
25        // Source 3: Interactive secure prompt (default).
26        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    // Open the vault, set the secret, and save.
35    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}