use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::sync::Arc;
use std::time::Duration;
use super::client::SandboxClient;
use super::manifest::Manifest;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Capability {
Shell,
Filesystem,
}
#[derive(Debug, Clone)]
pub struct SandboxConfig {
pub client: Arc<dyn SandboxClient>,
pub manifest: Manifest,
pub capabilities: HashSet<Capability>,
pub snapshot_on_stop: bool,
pub session_timeout: Duration,
pub command_timeout: Duration,
}
impl SandboxConfig {
pub fn new(
client: Arc<dyn SandboxClient>,
manifest: Manifest,
capabilities: HashSet<Capability>,
) -> Self {
Self {
client,
manifest,
capabilities,
snapshot_on_stop: false,
session_timeout: Duration::from_secs(600),
command_timeout: Duration::from_secs(120),
}
}
pub fn with_snapshot_on_stop(mut self, snapshot: bool) -> Self {
self.snapshot_on_stop = snapshot;
self
}
pub fn with_session_timeout(mut self, timeout: Duration) -> Self {
self.session_timeout = timeout;
self
}
pub fn with_command_timeout(mut self, timeout: Duration) -> Self {
self.command_timeout = timeout;
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SandboxConfigSpec {
pub manifest: Manifest,
pub capabilities: HashSet<Capability>,
pub snapshot_on_stop: bool,
pub session_timeout_secs: u64,
pub command_timeout_secs: u64,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn capability_equality() {
assert_eq!(Capability::Shell, Capability::Shell);
assert_eq!(Capability::Filesystem, Capability::Filesystem);
assert_ne!(Capability::Shell, Capability::Filesystem);
}
#[test]
fn capability_hash_set() {
let mut set = HashSet::new();
set.insert(Capability::Shell);
set.insert(Capability::Filesystem);
set.insert(Capability::Shell); assert_eq!(set.len(), 2);
}
#[test]
fn capability_serialization_roundtrip() {
let shell_json = serde_json::to_string(&Capability::Shell).unwrap();
let fs_json = serde_json::to_string(&Capability::Filesystem).unwrap();
let shell: Capability = serde_json::from_str(&shell_json).unwrap();
let fs: Capability = serde_json::from_str(&fs_json).unwrap();
assert_eq!(shell, Capability::Shell);
assert_eq!(fs, Capability::Filesystem);
}
#[test]
fn sandbox_config_spec_serialization_roundtrip() {
let spec = SandboxConfigSpec {
manifest: Manifest { entries: vec![] },
capabilities: HashSet::from([Capability::Shell, Capability::Filesystem]),
snapshot_on_stop: true,
session_timeout_secs: 600,
command_timeout_secs: 120,
};
let json = serde_json::to_string(&spec).unwrap();
let deserialized: SandboxConfigSpec = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, spec);
}
#[test]
fn sandbox_config_spec_empty_capabilities() {
let spec = SandboxConfigSpec {
manifest: Manifest { entries: vec![] },
capabilities: HashSet::new(),
snapshot_on_stop: false,
session_timeout_secs: 300,
command_timeout_secs: 60,
};
let json = serde_json::to_string(&spec).unwrap();
let deserialized: SandboxConfigSpec = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, spec);
}
}