1use serde::{Deserialize, Serialize};
10
11#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
13#[derive(Debug, Clone, Deserialize, Serialize)]
14pub struct SandboxConfig {
15 #[serde(default = "default_true")]
17 pub enabled: bool,
18
19 #[serde(default)]
21 pub default_mode: SandboxMode,
22
23 #[serde(default)]
25 pub network: NetworkConfig,
26
27 #[serde(default)]
29 pub sensitive_paths: SensitivePathsConfig,
30
31 #[serde(default)]
33 pub resource_limits: ResourceLimitsConfig,
34
35 #[serde(default)]
37 pub seccomp: SeccompConfig,
38
39 #[serde(default)]
41 pub external: ExternalSandboxConfig,
42}
43
44impl Default for SandboxConfig {
45 fn default() -> Self {
46 Self {
47 enabled: default_true(),
48 default_mode: SandboxMode::default(),
49 network: NetworkConfig::default(),
50 sensitive_paths: SensitivePathsConfig::default(),
51 resource_limits: ResourceLimitsConfig::default(),
52 seccomp: SeccompConfig::default(),
53 external: ExternalSandboxConfig::default(),
54 }
55 }
56}
57
58#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
60#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
61#[serde(rename_all = "snake_case")]
62pub enum SandboxMode {
63 #[default]
65 ReadOnly,
66 WorkspaceWrite,
68 DangerFullAccess,
70 External,
72}
73
74#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
76#[derive(Debug, Clone, Default, Deserialize, Serialize)]
77pub struct NetworkConfig {
78 #[serde(default)]
80 pub allow_all: bool,
81
82 #[serde(default)]
85 pub allowlist: Vec<NetworkAllowlistEntryConfig>,
86
87 #[serde(default)]
89 pub block_all: bool,
90}
91
92#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
94#[derive(Debug, Clone, Deserialize, Serialize)]
95pub struct NetworkAllowlistEntryConfig {
96 pub domain: String,
98 #[serde(default = "default_https_port")]
100 pub port: u16,
101}
102
103fn default_https_port() -> u16 {
104 443
105}
106
107#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
109#[derive(Debug, Clone, Deserialize, Serialize)]
110pub struct SensitivePathsConfig {
111 #[serde(default = "default_true")]
113 pub use_defaults: bool,
114
115 #[serde(default)]
117 pub additional: Vec<String>,
118
119 #[serde(default)]
121 pub exceptions: Vec<String>,
122}
123
124impl Default for SensitivePathsConfig {
125 fn default() -> Self {
126 Self {
127 use_defaults: default_true(),
128 additional: Vec::new(),
129 exceptions: Vec::new(),
130 }
131 }
132}
133
134#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
136#[derive(Debug, Clone, Default, Deserialize, Serialize)]
137pub struct ResourceLimitsConfig {
138 #[serde(default)]
140 pub preset: ResourceLimitsPreset,
141
142 #[serde(default)]
144 pub max_memory_mb: u64,
145
146 #[serde(default)]
148 pub max_pids: u32,
149
150 #[serde(default)]
152 pub max_disk_mb: u64,
153
154 #[serde(default)]
156 pub cpu_time_secs: u64,
157
158 #[serde(default)]
160 pub timeout_secs: u64,
161}
162
163#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
165#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
166#[serde(rename_all = "snake_case")]
167pub enum ResourceLimitsPreset {
168 Unlimited,
170 Conservative,
172 #[default]
174 Moderate,
175 Generous,
177 Custom,
179}
180
181#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
183#[derive(Debug, Clone, Deserialize, Serialize)]
184pub struct SeccompConfig {
185 #[serde(default = "default_true")]
187 pub enabled: bool,
188
189 #[serde(default)]
191 pub profile: SeccompProfilePreset,
192
193 #[serde(default)]
195 pub additional_blocked: Vec<String>,
196
197 #[serde(default)]
199 pub log_only: bool,
200}
201
202impl Default for SeccompConfig {
203 fn default() -> Self {
204 Self {
205 enabled: default_true(),
206 profile: SeccompProfilePreset::default(),
207 additional_blocked: Vec::new(),
208 log_only: false,
209 }
210 }
211}
212
213#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
215#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
216#[serde(rename_all = "snake_case")]
217pub enum SeccompProfilePreset {
218 #[default]
220 Strict,
221 Permissive,
223 Disabled,
225}
226
227#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
229#[derive(Debug, Clone, Default, Deserialize, Serialize)]
230pub struct ExternalSandboxConfig {
231 #[serde(default)]
233 pub sandbox_type: ExternalSandboxType,
234
235 #[serde(default)]
237 pub docker: DockerSandboxConfig,
238
239 #[serde(default)]
241 pub microvm: MicroVMSandboxConfig,
242}
243
244#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
246#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
247#[serde(rename_all = "snake_case")]
248pub enum ExternalSandboxType {
249 #[default]
251 None,
252 Docker,
254 MicroVM,
256 GVisor,
258}
259
260#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
262#[derive(Debug, Clone, Deserialize, Serialize)]
263pub struct DockerSandboxConfig {
264 #[serde(default = "default_docker_image")]
266 pub image: String,
267
268 #[serde(default)]
270 pub memory_limit: String,
271
272 #[serde(default)]
274 pub cpu_limit: String,
275
276 #[serde(default = "default_network_mode")]
278 pub network_mode: String,
279}
280
281fn default_docker_image() -> String {
282 "ubuntu:22.04".to_string()
283}
284
285fn default_network_mode() -> String {
286 "none".to_string()
287}
288
289impl Default for DockerSandboxConfig {
290 fn default() -> Self {
291 Self {
292 image: default_docker_image(),
293 memory_limit: String::new(),
294 cpu_limit: String::new(),
295 network_mode: default_network_mode(),
296 }
297 }
298}
299
300#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
302#[derive(Debug, Clone, Deserialize, Serialize)]
303pub struct MicroVMSandboxConfig {
304 #[serde(default)]
306 pub vmm: String,
307
308 #[serde(default)]
310 pub kernel_path: String,
311
312 #[serde(default)]
314 pub rootfs_path: String,
315
316 #[serde(default = "default_microvm_memory")]
318 pub memory_mb: u64,
319
320 #[serde(default = "default_vcpus")]
322 pub vcpus: u32,
323}
324
325fn default_microvm_memory() -> u64 {
326 512
327}
328
329fn default_vcpus() -> u32 {
330 1
331}
332
333impl Default for MicroVMSandboxConfig {
334 fn default() -> Self {
335 Self {
336 vmm: String::new(),
337 kernel_path: String::new(),
338 rootfs_path: String::new(),
339 memory_mb: default_microvm_memory(),
340 vcpus: default_vcpus(),
341 }
342 }
343}
344
345#[inline]
346const fn default_true() -> bool {
347 true
348}
349
350#[cfg(test)]
351mod tests {
352 use super::*;
353
354 #[test]
355 fn test_sandbox_config_default() {
356 let config = SandboxConfig::default();
357 assert!(config.enabled);
358 assert_eq!(config.default_mode, SandboxMode::ReadOnly);
359 }
360
361 #[test]
362 fn test_network_config_default() {
363 let config = NetworkConfig::default();
364 assert!(!config.allow_all);
365 assert!(!config.block_all);
366 assert!(config.allowlist.is_empty());
367 }
368
369 #[test]
370 fn test_resource_limits_config_default() {
371 let config = ResourceLimitsConfig::default();
372 assert_eq!(config.preset, ResourceLimitsPreset::Moderate);
373 }
374
375 #[test]
376 fn test_seccomp_config_default() {
377 let config = SeccompConfig::default();
378 assert!(config.enabled);
379 assert_eq!(config.profile, SeccompProfilePreset::Strict);
380 }
381}