Skip to main content

envvault/cli/commands/
run.rs

1//! `envvault run` — inject secrets into a child process.
2
3use std::process::Command;
4
5use crate::cli::output;
6use crate::cli::{load_keyfile, prompt_password_for_vault, vault_path, Cli};
7use crate::errors::{EnvVaultError, Result};
8use crate::vault::VaultStore;
9
10/// Execute the `run` command.
11pub fn execute(cli: &Cli, command: &[String], clean_env: bool) -> Result<()> {
12    if command.is_empty() {
13        return Err(EnvVaultError::NoCommandSpecified);
14    }
15
16    let path = vault_path(cli)?;
17
18    let keyfile = load_keyfile(cli)?;
19    let vault_id = path.to_string_lossy();
20    let password = prompt_password_for_vault(Some(&vault_id))?;
21    let store = VaultStore::open(&path, password.as_bytes(), keyfile.as_deref())?;
22
23    // Decrypt all secrets into memory.
24    let secrets = store.get_all_secrets()?;
25
26    if clean_env {
27        output::success(&format!(
28            "Injected {} secrets into clean environment",
29            secrets.len()
30        ));
31    } else {
32        output::success(&format!(
33            "Injected {} secrets into environment",
34            secrets.len()
35        ));
36    }
37
38    // Build the child process.
39    let program = &command[0];
40    let args = &command[1..];
41
42    let mut cmd = Command::new(program);
43    cmd.args(args);
44
45    if clean_env {
46        // Start with a completely empty environment — only vault secrets.
47        cmd.env_clear();
48    }
49
50    let status = cmd.envs(&secrets).status()?;
51
52    // Forward the child's exit code.
53    match status.code() {
54        Some(0) => Ok(()),
55        Some(code) => Err(EnvVaultError::ChildProcessFailed(code)),
56        None => Err(EnvVaultError::CommandFailed(
57            "child process terminated by signal".into(),
58        )),
59    }
60}