use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct SandboxConfig {
#[serde(default = "default_false")]
pub enabled: bool,
#[serde(default)]
pub default_mode: SandboxMode,
#[serde(default)]
pub network: NetworkConfig,
#[serde(default)]
pub sensitive_paths: SensitivePathsConfig,
#[serde(default)]
pub resource_limits: ResourceLimitsConfig,
#[serde(default)]
pub seccomp: SeccompConfig,
#[serde(default)]
pub external: ExternalSandboxConfig,
}
impl Default for SandboxConfig {
fn default() -> Self {
Self {
enabled: default_false(),
default_mode: SandboxMode::default(),
network: NetworkConfig::default(),
sensitive_paths: SensitivePathsConfig::default(),
resource_limits: ResourceLimitsConfig::default(),
seccomp: SeccompConfig::default(),
external: ExternalSandboxConfig::default(),
}
}
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum SandboxMode {
#[default]
ReadOnly,
WorkspaceWrite,
DangerFullAccess,
External,
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct NetworkConfig {
#[serde(default)]
pub allow_all: bool,
#[serde(default)]
pub allowlist: Vec<NetworkAllowlistEntryConfig>,
#[serde(default)]
pub block_all: bool,
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct NetworkAllowlistEntryConfig {
pub domain: String,
#[serde(default = "default_https_port")]
pub port: u16,
}
fn default_https_port() -> u16 {
443
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct SensitivePathsConfig {
#[serde(default = "default_true")]
pub use_defaults: bool,
#[serde(default)]
pub additional: Vec<String>,
#[serde(default)]
pub exceptions: Vec<String>,
}
impl Default for SensitivePathsConfig {
fn default() -> Self {
Self {
use_defaults: default_true(),
additional: Vec::new(),
exceptions: Vec::new(),
}
}
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct ResourceLimitsConfig {
#[serde(default)]
pub preset: ResourceLimitsPreset,
#[serde(default)]
pub max_memory_mb: u64,
#[serde(default)]
pub max_pids: u32,
#[serde(default)]
pub max_disk_mb: u64,
#[serde(default)]
pub cpu_time_secs: u64,
#[serde(default)]
pub timeout_secs: u64,
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ResourceLimitsPreset {
Unlimited,
Conservative,
#[default]
Moderate,
Generous,
Custom,
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct SeccompConfig {
#[serde(default = "default_true")]
pub enabled: bool,
#[serde(default)]
pub profile: SeccompProfilePreset,
#[serde(default)]
pub additional_blocked: Vec<String>,
#[serde(default)]
pub log_only: bool,
}
impl Default for SeccompConfig {
fn default() -> Self {
Self {
enabled: default_true(),
profile: SeccompProfilePreset::default(),
additional_blocked: Vec::new(),
log_only: false,
}
}
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum SeccompProfilePreset {
#[default]
Strict,
Permissive,
Disabled,
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct ExternalSandboxConfig {
#[serde(default)]
pub sandbox_type: ExternalSandboxType,
#[serde(default)]
pub docker: DockerSandboxConfig,
#[serde(default)]
pub microvm: MicroVMSandboxConfig,
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ExternalSandboxType {
#[default]
None,
Docker,
MicroVM,
GVisor,
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DockerSandboxConfig {
#[serde(default = "default_docker_image")]
pub image: String,
#[serde(default)]
pub memory_limit: String,
#[serde(default)]
pub cpu_limit: String,
#[serde(default = "default_network_mode")]
pub network_mode: String,
}
fn default_docker_image() -> String {
"ubuntu:22.04".to_string()
}
fn default_network_mode() -> String {
"none".to_string()
}
impl Default for DockerSandboxConfig {
fn default() -> Self {
Self {
image: default_docker_image(),
memory_limit: String::new(),
cpu_limit: String::new(),
network_mode: default_network_mode(),
}
}
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MicroVMSandboxConfig {
#[serde(default)]
pub vmm: String,
#[serde(default)]
pub kernel_path: String,
#[serde(default)]
pub rootfs_path: String,
#[serde(default = "default_microvm_memory")]
pub memory_mb: u64,
#[serde(default = "default_vcpus")]
pub vcpus: u32,
}
fn default_microvm_memory() -> u64 {
512
}
fn default_vcpus() -> u32 {
1
}
impl Default for MicroVMSandboxConfig {
fn default() -> Self {
Self {
vmm: String::new(),
kernel_path: String::new(),
rootfs_path: String::new(),
memory_mb: default_microvm_memory(),
vcpus: default_vcpus(),
}
}
}
#[inline]
const fn default_false() -> bool {
false
}
#[inline]
const fn default_true() -> bool {
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sandbox_config_default() {
let config = SandboxConfig::default();
assert!(!config.enabled);
assert_eq!(config.default_mode, SandboxMode::ReadOnly);
}
#[test]
fn test_network_config_default() {
let config = NetworkConfig::default();
assert!(!config.allow_all);
assert!(!config.block_all);
assert!(config.allowlist.is_empty());
}
#[test]
fn test_resource_limits_config_default() {
let config = ResourceLimitsConfig::default();
assert_eq!(config.preset, ResourceLimitsPreset::Moderate);
}
#[test]
fn test_seccomp_config_default() {
let config = SeccompConfig::default();
assert!(config.enabled);
assert_eq!(config.profile, SeccompProfilePreset::Strict);
}
}