configbuilder-pattern-substitution 0.1.0

configbuilder-pattern: substitution domain, trait contract + reference implementation. No -svc counterpart.
Documentation
use crate::{SubstitutionError, SubstitutionPolicy};

/// Allows only environment variables whose names start with one of the given prefixes.
#[derive(Debug)]
pub struct PrefixWhitelistPolicy {
    prefixes: Vec<String>,
}

impl PrefixWhitelistPolicy {
    /// Create a prefix-based whitelist policy.
    pub fn new(prefixes: Vec<String>) -> Self {
        Self { prefixes }
    }

    /// Return the configured allowed prefixes.
    pub fn prefixes(&self) -> &[String] {
        &self.prefixes
    }
}

impl SubstitutionPolicy for PrefixWhitelistPolicy {
    fn validate(&self, var_name: &str) -> Result<(), SubstitutionError> {
        if self
            .prefixes()
            .iter()
            .any(|p| var_name.starts_with(p.as_str()))
        {
            Ok(())
        } else {
            Err(SubstitutionError::VariableRejected {
                var_name: var_name.to_string(),
                reason: format!(
                    "does not match any allowed prefix: {}",
                    self.prefixes().join(", ")
                ),
                policy: self.description(),
            })
        }
    }

    fn description(&self) -> String {
        format!("PrefixWhitelist({})", self.prefixes().join(", "))
    }
}