use std::collections::HashMap;
use std::path::PathBuf;
pub mod audit;
pub mod capabilities;
pub mod resource_limits;
pub mod audit_impl;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HostSpec {
pub host: String,
pub ports: Option<PortRange>,
pub secure: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PortRange {
pub start: u16,
pub end: u16,
}
impl PortRange {
pub fn new(start: u16, end: u16) -> Self {
assert!(start <= end, "Start port must be less than or equal to end port");
Self { start, end }
}
pub fn single(port: u16) -> Self {
Self {
start: port,
end: port,
}
}
pub fn contains(&self, port: u16) -> bool {
port >= self.start && port <= self.end
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum NetworkCapability {
None,
Loopback,
AllowedHosts(Vec<HostSpec>),
AllowedPorts(Vec<PortRange>),
Full,
}
impl Default for NetworkCapability {
fn default() -> Self {
Self::None
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct FilesystemCapability {
pub readable_dirs: Vec<PathBuf>,
pub writable_dirs: Vec<PathBuf>,
pub max_file_size: Option<u64>,
pub allow_create: bool,
pub allow_delete: bool,
}
impl Default for FilesystemCapability {
fn default() -> Self {
Self {
readable_dirs: Vec::new(),
writable_dirs: Vec::new(),
max_file_size: None,
allow_create: false,
allow_delete: false,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum EnvironmentCapability {
None,
Allowlist(Vec<String>),
Denylist(Vec<String>),
Full,
}
impl Default for EnvironmentCapability {
fn default() -> Self {
Self::None
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ProcessCapability {
None,
AllowedCommands(Vec<String>),
Full,
}
impl Default for ProcessCapability {
fn default() -> Self {
Self::None
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TimeCapability {
ReadOnly,
Full,
}
impl Default for TimeCapability {
fn default() -> Self {
Self::ReadOnly
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum RandomCapability {
None,
PseudoOnly,
Full,
}
impl Default for RandomCapability {
fn default() -> Self {
Self::PseudoOnly
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum CustomCapability {
Boolean(bool),
Numeric {
value: i64,
min: i64,
max: i64,
},
String(String),
StringList(Vec<String>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct Capabilities {
pub network: NetworkCapability,
pub filesystem: FilesystemCapability,
pub environment: EnvironmentCapability,
pub process: ProcessCapability,
pub time: TimeCapability,
pub random: RandomCapability,
pub custom: HashMap<String, CustomCapability>,
}
impl Capabilities {
pub fn minimal() -> Self {
Self {
network: NetworkCapability::None,
filesystem: FilesystemCapability::default(),
environment: EnvironmentCapability::None,
process: ProcessCapability::None,
time: TimeCapability::ReadOnly,
random: RandomCapability::PseudoOnly,
custom: HashMap::new(),
}
}
pub fn development() -> Self {
Self {
network: NetworkCapability::Loopback,
filesystem: FilesystemCapability {
readable_dirs: vec![std::env::current_dir().unwrap_or_default()],
writable_dirs: vec![std::env::temp_dir()],
max_file_size: Some(10 * 1024 * 1024), allow_create: true,
allow_delete: false,
},
environment: EnvironmentCapability::Allowlist(vec![
"PATH".to_string(),
"TEMP".to_string(),
"TMP".to_string(),
]),
process: ProcessCapability::None,
time: TimeCapability::ReadOnly,
random: RandomCapability::Full,
custom: HashMap::new(),
}
}
pub fn add_custom(&mut self, name: &str, capability: CustomCapability) {
self.custom.insert(name.to_string(), capability);
}
pub fn get_custom(&self, name: &str) -> Option<&CustomCapability> {
self.custom.get(name)
}
}
impl Default for Capabilities {
fn default() -> Self {
Self::minimal()
}
}
#[derive(Debug, Clone)]
pub struct MemoryLimits {
pub max_memory_pages: u32,
pub reserved_memory_pages: u32,
pub max_growth_rate: Option<u32>,
pub max_tables: u32,
}
impl Default for MemoryLimits {
fn default() -> Self {
Self {
max_memory_pages: 160, reserved_memory_pages: 16, max_growth_rate: Some(10),
max_tables: 1,
}
}
}
#[derive(Debug, Clone)]
pub struct CpuLimits {
pub max_execution_time_ms: u64,
pub cpu_usage_percentage: Option<u8>,
pub max_threads: Option<u32>,
}
impl Default for CpuLimits {
fn default() -> Self {
Self {
max_execution_time_ms: 5000, cpu_usage_percentage: Some(50), max_threads: Some(1), }
}
}
#[derive(Debug, Clone)]
pub struct IoLimits {
pub max_open_files: u32,
pub max_read_bytes_per_second: Option<u64>,
pub max_write_bytes_per_second: Option<u64>,
pub max_total_read_bytes: Option<u64>,
pub max_total_write_bytes: Option<u64>,
}
impl Default for IoLimits {
fn default() -> Self {
Self {
max_open_files: 10,
max_read_bytes_per_second: Some(1024 * 1024), max_write_bytes_per_second: Some(1024 * 1024), max_total_read_bytes: Some(10 * 1024 * 1024), max_total_write_bytes: Some(5 * 1024 * 1024), }
}
}
#[derive(Debug, Clone)]
pub struct TimeLimits {
pub max_total_time_ms: u64,
pub max_idle_time_ms: Option<u64>,
}
impl Default for TimeLimits {
fn default() -> Self {
Self {
max_total_time_ms: 30000, max_idle_time_ms: Some(5000), }
}
}
#[derive(Debug, Clone)]
pub struct ResourceLimits {
pub memory: MemoryLimits,
pub cpu: CpuLimits,
pub io: IoLimits,
pub time: TimeLimits,
pub fuel: Option<u64>,
}
impl Default for ResourceLimits {
fn default() -> Self {
Self {
memory: MemoryLimits::default(),
cpu: CpuLimits::default(),
io: IoLimits::default(),
time: TimeLimits::default(),
fuel: Some(10_000_000), }
}
}