1use std::collections::HashMap;
4use std::path::PathBuf;
5
6pub mod audit;
7pub mod capabilities;
8pub mod resource_limits;
9pub mod audit_impl;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct HostSpec {
14 pub host: String,
16
17 pub ports: Option<PortRange>,
19
20 pub secure: bool,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct PortRange {
27 pub start: u16,
29
30 pub end: u16,
32}
33
34impl PortRange {
35 pub fn new(start: u16, end: u16) -> Self {
37 assert!(start <= end, "Start port must be less than or equal to end port");
38 Self { start, end }
39 }
40
41 pub fn single(port: u16) -> Self {
43 Self {
44 start: port,
45 end: port,
46 }
47 }
48
49 pub fn contains(&self, port: u16) -> bool {
51 port >= self.start && port <= self.end
52 }
53}
54
55#[derive(Debug, Clone, PartialEq)]
57pub enum NetworkCapability {
58 None,
60
61 Loopback,
63
64 AllowedHosts(Vec<HostSpec>),
66
67 AllowedPorts(Vec<PortRange>),
69
70 Full,
72}
73
74impl Default for NetworkCapability {
75 fn default() -> Self {
76 Self::None
77 }
78}
79
80#[derive(Debug, Clone, PartialEq)]
82pub struct FilesystemCapability {
83 pub readable_dirs: Vec<PathBuf>,
85
86 pub writable_dirs: Vec<PathBuf>,
88
89 pub max_file_size: Option<u64>,
91
92 pub allow_create: bool,
94
95 pub allow_delete: bool,
97}
98
99impl Default for FilesystemCapability {
100 fn default() -> Self {
101 Self {
102 readable_dirs: Vec::new(),
103 writable_dirs: Vec::new(),
104 max_file_size: None,
105 allow_create: false,
106 allow_delete: false,
107 }
108 }
109}
110
111#[derive(Debug, Clone, PartialEq)]
113pub enum EnvironmentCapability {
114 None,
116
117 Allowlist(Vec<String>),
119
120 Denylist(Vec<String>),
122
123 Full,
125}
126
127impl Default for EnvironmentCapability {
128 fn default() -> Self {
129 Self::None
130 }
131}
132
133#[derive(Debug, Clone, PartialEq)]
135pub enum ProcessCapability {
136 None,
138
139 AllowedCommands(Vec<String>),
141
142 Full,
144}
145
146impl Default for ProcessCapability {
147 fn default() -> Self {
148 Self::None
149 }
150}
151
152#[derive(Debug, Clone, PartialEq)]
154pub enum TimeCapability {
155 ReadOnly,
157
158 Full,
160}
161
162impl Default for TimeCapability {
163 fn default() -> Self {
164 Self::ReadOnly
165 }
166}
167
168#[derive(Debug, Clone, PartialEq)]
170pub enum RandomCapability {
171 None,
173
174 PseudoOnly,
176
177 Full,
179}
180
181impl Default for RandomCapability {
182 fn default() -> Self {
183 Self::PseudoOnly
184 }
185}
186
187#[derive(Debug, Clone, PartialEq)]
189pub enum CustomCapability {
190 Boolean(bool),
192
193 Numeric {
195 value: i64,
197 min: i64,
199 max: i64,
201 },
202
203 String(String),
205
206 StringList(Vec<String>),
208}
209
210#[derive(Debug, Clone, PartialEq)]
212pub struct Capabilities {
213 pub network: NetworkCapability,
215
216 pub filesystem: FilesystemCapability,
218
219 pub environment: EnvironmentCapability,
221
222 pub process: ProcessCapability,
224
225 pub time: TimeCapability,
227
228 pub random: RandomCapability,
230
231 pub custom: HashMap<String, CustomCapability>,
233}
234
235impl Capabilities {
236 pub fn minimal() -> Self {
238 Self {
239 network: NetworkCapability::None,
240 filesystem: FilesystemCapability::default(),
241 environment: EnvironmentCapability::None,
242 process: ProcessCapability::None,
243 time: TimeCapability::ReadOnly,
244 random: RandomCapability::PseudoOnly,
245 custom: HashMap::new(),
246 }
247 }
248
249 pub fn development() -> Self {
251 Self {
252 network: NetworkCapability::Loopback,
253 filesystem: FilesystemCapability {
254 readable_dirs: vec![std::env::current_dir().unwrap_or_default()],
255 writable_dirs: vec![std::env::temp_dir()],
256 max_file_size: Some(10 * 1024 * 1024), allow_create: true,
258 allow_delete: false,
259 },
260 environment: EnvironmentCapability::Allowlist(vec![
261 "PATH".to_string(),
262 "TEMP".to_string(),
263 "TMP".to_string(),
264 ]),
265 process: ProcessCapability::None,
266 time: TimeCapability::ReadOnly,
267 random: RandomCapability::Full,
268 custom: HashMap::new(),
269 }
270 }
271
272 pub fn add_custom(&mut self, name: &str, capability: CustomCapability) {
274 self.custom.insert(name.to_string(), capability);
275 }
276
277 pub fn get_custom(&self, name: &str) -> Option<&CustomCapability> {
279 self.custom.get(name)
280 }
281}
282
283impl Default for Capabilities {
284 fn default() -> Self {
285 Self::minimal()
286 }
287}
288
289#[derive(Debug, Clone)]
291pub struct MemoryLimits {
292 pub max_memory_pages: u32,
294
295 pub reserved_memory_pages: u32,
297
298 pub max_growth_rate: Option<u32>,
300
301 pub max_tables: u32,
303}
304
305impl Default for MemoryLimits {
306 fn default() -> Self {
307 Self {
308 max_memory_pages: 160, reserved_memory_pages: 16, max_growth_rate: Some(10),
311 max_tables: 1,
312 }
313 }
314}
315
316#[derive(Debug, Clone)]
318pub struct CpuLimits {
319 pub max_execution_time_ms: u64,
321
322 pub cpu_usage_percentage: Option<u8>,
324
325 pub max_threads: Option<u32>,
327}
328
329impl Default for CpuLimits {
330 fn default() -> Self {
331 Self {
332 max_execution_time_ms: 5000, cpu_usage_percentage: Some(50), max_threads: Some(1), }
336 }
337}
338
339#[derive(Debug, Clone)]
341pub struct IoLimits {
342 pub max_open_files: u32,
344
345 pub max_read_bytes_per_second: Option<u64>,
347
348 pub max_write_bytes_per_second: Option<u64>,
350
351 pub max_total_read_bytes: Option<u64>,
353
354 pub max_total_write_bytes: Option<u64>,
356}
357
358impl Default for IoLimits {
359 fn default() -> Self {
360 Self {
361 max_open_files: 10,
362 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), }
367 }
368}
369
370#[derive(Debug, Clone)]
372pub struct TimeLimits {
373 pub max_total_time_ms: u64,
375
376 pub max_idle_time_ms: Option<u64>,
378}
379
380impl Default for TimeLimits {
381 fn default() -> Self {
382 Self {
383 max_total_time_ms: 30000, max_idle_time_ms: Some(5000), }
386 }
387}
388
389#[derive(Debug, Clone)]
391pub struct ResourceLimits {
392 pub memory: MemoryLimits,
394
395 pub cpu: CpuLimits,
397
398 pub io: IoLimits,
400
401 pub time: TimeLimits,
403
404 pub fuel: Option<u64>,
406}
407
408impl Default for ResourceLimits {
409 fn default() -> Self {
410 Self {
411 memory: MemoryLimits::default(),
412 cpu: CpuLimits::default(),
413 io: IoLimits::default(),
414 time: TimeLimits::default(),
415 fuel: Some(10_000_000), }
417 }
418}