use std::collections::HashSet;
use super::{PolicyError, Unrestricted};
pub trait EnvPolicy: Send + Sync + 'static {
fn policy_name(&self) -> &'static str {
std::any::type_name::<Self>()
}
fn check_get(&self, key: &str) -> Result<(), PolicyError>;
fn check_set(&self, key: &str) -> Result<(), PolicyError>;
}
impl EnvPolicy for Unrestricted {
fn check_get(&self, _key: &str) -> Result<(), PolicyError> {
Ok(())
}
fn check_set(&self, _key: &str) -> Result<(), PolicyError> {
Ok(())
}
}
#[derive(Debug)]
pub struct EnvAllowList {
allowed_keys: HashSet<String>,
allow_set: bool,
}
impl EnvAllowList {
pub fn new<I, S>(keys: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
Self {
allowed_keys: keys.into_iter().map(Into::into).collect::<HashSet<_>>(),
allow_set: true,
}
}
pub fn read_only(mut self) -> Self {
self.allow_set = false;
self
}
}
impl EnvPolicy for EnvAllowList {
fn check_get(&self, key: &str) -> Result<(), PolicyError> {
if self.allowed_keys.contains(key) {
Ok(())
} else {
Err(PolicyError::new(format!(
"read denied: env var '{key}' is not in the allow list"
)))
}
}
fn check_set(&self, key: &str) -> Result<(), PolicyError> {
if !self.allow_set {
return Err(PolicyError::new(format!(
"set denied: env is read-only (key '{key}')"
)));
}
if self.allowed_keys.contains(key) {
Ok(())
} else {
Err(PolicyError::new(format!(
"set denied: env var '{key}' is not in the allow list"
)))
}
}
}