Skip to main content

authy/subprocess/
mod.rs

1use std::collections::HashMap;
2use std::process::Command;
3
4use crate::error::{AuthyError, Result};
5
6/// Options for naming environment variables when injecting secrets.
7#[derive(Debug, Clone, Default)]
8pub struct NamingOptions {
9    pub uppercase: bool,
10    pub replace_dash: Option<char>,
11    pub prefix: Option<String>,
12}
13
14/// Transform a secret name into an environment variable name.
15pub fn transform_name(name: &str, opts: &NamingOptions) -> String {
16    let mut result = name.to_string();
17
18    if let Some(replacement) = opts.replace_dash {
19        result = result.replace('-', &replacement.to_string());
20    }
21
22    if opts.uppercase {
23        result = result.to_uppercase();
24    }
25
26    if let Some(ref prefix) = opts.prefix {
27        result = format!("{}{}", prefix, result);
28    }
29
30    result
31}
32
33/// Run a subprocess with the given secrets injected as environment variables.
34/// Returns the exit code of the subprocess.
35pub fn run_with_secrets(
36    command: &[String],
37    secrets: &HashMap<String, String>,
38    naming: &NamingOptions,
39) -> Result<i32> {
40    if command.is_empty() {
41        return Err(AuthyError::Other("No command specified".into()));
42    }
43
44    let env_vars: HashMap<String, String> = secrets
45        .iter()
46        .map(|(name, value)| (transform_name(name, naming), value.clone()))
47        .collect();
48
49    let status = Command::new(&command[0])
50        .args(&command[1..])
51        .envs(&env_vars)
52        .env_remove("AUTHY_PASSPHRASE")
53        .env_remove("AUTHY_TOKEN")
54        .status()
55        .map_err(|e| AuthyError::Other(format!("Failed to run command '{}': {}", command[0], e)))?;
56
57    Ok(status.code().unwrap_or(1))
58}