secenv 0.0.0

Secure environments.
use {
    crate::pgp::PgpManager,
    anyhow::Context,
    serde::{
        Deserialize,
        Serialize,
    },
    std::collections::HashMap,
};

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct Config {
    pub profiles: HashMap<String, ConfigProfile>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ConfigProfile {
    #[serde(default)]
    pub propagate: Option<Vec<String>>,
    pub vars: HashMap<String, ValueProvider>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ValueProvider {
    Literal(String),
    Environment(String),
    File(String),
    #[serde(rename = "pgp")]
    PGP {
        key: String,
        value: String,
    },
}

impl ValueProvider {
    pub fn get_value(&self) -> Result<String, anyhow::Error> {
        match self {
            | ValueProvider::Literal(value) => Ok(value.clone()),
            | ValueProvider::Environment(value) => {
                Ok(std::env::var(value).context(format!("Failed to get environment variable: {}", value))?)
            },
            | ValueProvider::File(value) => {
                Ok(std::fs::read_to_string(value).context(format!("Failed to read file: {}", value))?)
            },
            | ValueProvider::PGP { key, value } => {
                let pgp_manager = PgpManager::new().context("Failed to initialize PGP manager")?;

                pgp_manager
                    .decrypt(key, value)
                    .context(format!("Failed to decrypt value using PGP key {}", key))
            },
        }
    }
}