use tracing::{debug, warn};
use crate::module::traits::ModuleError;
pub struct NetworkSandbox {
allow_network: bool,
#[allow(dead_code)]
allowed_endpoints: Vec<String>,
}
impl NetworkSandbox {
pub fn new() -> Self {
Self {
allow_network: false,
allowed_endpoints: Vec::new(),
}
}
pub fn with_allowed_endpoints(endpoints: Vec<String>) -> Self {
Self {
allow_network: !endpoints.is_empty(),
allowed_endpoints: endpoints,
}
}
pub fn is_network_allowed(&self) -> bool {
self.allow_network
}
pub fn validate_network_operation(&self, operation: &str) -> Result<(), ModuleError> {
if !self.allow_network {
warn!(
"Module attempted network operation: {} (network access denied)",
operation
);
return Err(ModuleError::OperationError(format!(
"Network access denied: modules cannot make network connections. Operation: {operation}"
)));
}
debug!("Network operation allowed: {}", operation);
Ok(())
}
pub fn validate_endpoint(&self, endpoint: &str) -> Result<(), ModuleError> {
if !self.allow_network {
return self.validate_network_operation("connect");
}
if !self.allowed_endpoints.is_empty() {
let allowed = self
.allowed_endpoints
.iter()
.any(|e| endpoint.starts_with(e));
if !allowed {
warn!(
"Module attempted to connect to unauthorized endpoint: {}",
endpoint
);
return Err(ModuleError::OperationError(format!(
"Endpoint not allowed: {endpoint} (not in allowed list)"
)));
}
}
debug!("Network endpoint validated: {}", endpoint);
Ok(())
}
}
impl Default for NetworkSandbox {
fn default() -> Self {
Self::new()
}
}