1use crate::env_helpers::default_true;
10use serde::{Deserialize, Serialize};
11
12#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
14#[derive(Debug, Clone, Deserialize, Serialize)]
15pub struct SandboxConfig {
16 #[serde(default = "default_false")]
18 pub enabled: bool,
19
20 #[serde(default)]
22 pub default_mode: SandboxMode,
23
24 #[serde(default)]
26 pub network: NetworkConfig,
27
28 #[serde(default)]
30 pub sensitive_paths: SensitivePathsConfig,
31
32 #[serde(default)]
34 pub resource_limits: ResourceLimitsConfig,
35
36 #[serde(default)]
38 pub seccomp: SeccompConfig,
39
40 #[serde(default)]
42 pub external: ExternalSandboxConfig,
43}
44
45impl Default for SandboxConfig {
46 fn default() -> Self {
47 Self {
48 enabled: default_false(),
49 default_mode: SandboxMode::default(),
50 network: NetworkConfig::default(),
51 sensitive_paths: SensitivePathsConfig::default(),
52 resource_limits: ResourceLimitsConfig::default(),
53 seccomp: SeccompConfig::default(),
54 external: ExternalSandboxConfig::default(),
55 }
56 }
57}
58
59#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
61#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
62#[serde(rename_all = "snake_case")]
63pub enum SandboxMode {
64 #[default]
66 ReadOnly,
67 WorkspaceWrite,
69 DangerFullAccess,
71 External,
73}
74
75#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
77#[derive(Debug, Clone, Default, Deserialize, Serialize)]
78pub struct NetworkConfig {
79 #[serde(default)]
81 pub allow_all: bool,
82
83 #[serde(default)]
86 pub allowlist: Vec<NetworkAllowlistEntryConfig>,
87
88 #[serde(default)]
90 pub block_all: bool,
91}
92
93#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
95#[derive(Debug, Clone, Deserialize, Serialize)]
96pub struct NetworkAllowlistEntryConfig {
97 pub domain: String,
99 #[serde(default = "default_https_port")]
101 pub port: u16,
102}
103
104fn default_https_port() -> u16 {
105 443
106}
107
108#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
110#[derive(Debug, Clone, Deserialize, Serialize)]
111pub struct SensitivePathsConfig {
112 #[serde(default = "default_true")]
114 pub use_defaults: bool,
115
116 #[serde(default)]
118 pub additional: Vec<String>,
119
120 #[serde(default)]
122 pub exceptions: Vec<String>,
123}
124
125impl Default for SensitivePathsConfig {
126 fn default() -> Self {
127 Self {
128 use_defaults: default_true(),
129 additional: Vec::new(),
130 exceptions: Vec::new(),
131 }
132 }
133}
134
135#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
137#[derive(Debug, Clone, Default, Deserialize, Serialize)]
138pub struct ResourceLimitsConfig {
139 #[serde(default)]
141 pub preset: ResourceLimitsPreset,
142
143 #[serde(default)]
145 pub max_memory_mb: u64,
146
147 #[serde(default)]
149 pub max_pids: u32,
150
151 #[serde(default)]
153 pub max_disk_mb: u64,
154
155 #[serde(default)]
157 pub cpu_time_secs: u64,
158
159 #[serde(default)]
161 pub timeout_secs: u64,
162}
163
164#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
166#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
167#[serde(rename_all = "snake_case")]
168pub enum ResourceLimitsPreset {
169 Unlimited,
171 Conservative,
173 #[default]
175 Moderate,
176 Generous,
178 Custom,
180}
181
182#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
184#[derive(Debug, Clone, Deserialize, Serialize)]
185pub struct SeccompConfig {
186 #[serde(default = "default_true")]
188 pub enabled: bool,
189
190 #[serde(default)]
192 pub profile: SeccompProfilePreset,
193
194 #[serde(default)]
196 pub additional_blocked: Vec<String>,
197
198 #[serde(default)]
200 pub log_only: bool,
201}
202
203impl Default for SeccompConfig {
204 fn default() -> Self {
205 Self {
206 enabled: default_true(),
207 profile: SeccompProfilePreset::default(),
208 additional_blocked: Vec::new(),
209 log_only: false,
210 }
211 }
212}
213
214#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
216#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
217#[serde(rename_all = "snake_case")]
218pub enum SeccompProfilePreset {
219 #[default]
221 Strict,
222 Permissive,
224 Disabled,
226}
227
228#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
230#[derive(Debug, Clone, Default, Deserialize, Serialize)]
231pub struct ExternalSandboxConfig {
232 #[serde(default)]
234 pub sandbox_type: ExternalSandboxType,
235
236 #[serde(default)]
238 pub docker: DockerSandboxConfig,
239
240 #[serde(default)]
242 pub microvm: MicroVMSandboxConfig,
243}
244
245#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
247#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
248#[serde(rename_all = "snake_case")]
249pub enum ExternalSandboxType {
250 #[default]
252 None,
253 Docker,
255 MicroVM,
257 GVisor,
259}
260
261#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
263#[derive(Debug, Clone, Deserialize, Serialize)]
264pub struct DockerSandboxConfig {
265 #[serde(default = "default_docker_image")]
267 pub image: String,
268
269 #[serde(default)]
271 pub memory_limit: String,
272
273 #[serde(default)]
275 pub cpu_limit: String,
276
277 #[serde(default = "default_network_mode")]
279 pub network_mode: String,
280}
281
282fn default_docker_image() -> String {
283 "ubuntu:22.04".to_string()
284}
285
286fn default_network_mode() -> String {
287 "none".to_string()
288}
289
290impl Default for DockerSandboxConfig {
291 fn default() -> Self {
292 Self {
293 image: default_docker_image(),
294 memory_limit: String::new(),
295 cpu_limit: String::new(),
296 network_mode: default_network_mode(),
297 }
298 }
299}
300
301#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
303#[derive(Debug, Clone, Deserialize, Serialize)]
304pub struct MicroVMSandboxConfig {
305 #[serde(default)]
307 pub vmm: String,
308
309 #[serde(default)]
311 pub kernel_path: String,
312
313 #[serde(default)]
315 pub rootfs_path: String,
316
317 #[serde(default = "default_microvm_memory")]
319 pub memory_mb: u64,
320
321 #[serde(default = "default_vcpus")]
323 pub vcpus: u32,
324}
325
326fn default_microvm_memory() -> u64 {
327 512
328}
329
330fn default_vcpus() -> u32 {
331 1
332}
333
334impl Default for MicroVMSandboxConfig {
335 fn default() -> Self {
336 Self {
337 vmm: String::new(),
338 kernel_path: String::new(),
339 rootfs_path: String::new(),
340 memory_mb: default_microvm_memory(),
341 vcpus: default_vcpus(),
342 }
343 }
344}
345
346#[inline]
347const fn default_false() -> bool {
348 false
349}
350
351#[cfg(test)]
352mod tests {
353 use super::*;
354
355 #[test]
356 fn test_sandbox_config_default() {
357 let config = SandboxConfig::default();
358 assert!(!config.enabled);
359 assert_eq!(config.default_mode, SandboxMode::ReadOnly);
360 }
361
362 #[test]
363 fn test_network_config_default() {
364 let config = NetworkConfig::default();
365 assert!(!config.allow_all);
366 assert!(!config.block_all);
367 assert!(config.allowlist.is_empty());
368 }
369
370 #[test]
371 fn test_resource_limits_config_default() {
372 let config = ResourceLimitsConfig::default();
373 assert_eq!(config.preset, ResourceLimitsPreset::Moderate);
374 }
375
376 #[test]
377 fn test_seccomp_config_default() {
378 let config = SeccompConfig::default();
379 assert!(config.enabled);
380 assert_eq!(config.profile, SeccompProfilePreset::Strict);
381 }
382}