Skip to main content

microsandbox_types/
exec.rs

1//! Sandbox-owned execution admission and I/O policy.
2
3use serde::{Deserialize, Serialize};
4
5//--------------------------------------------------------------------------------------------------
6// Constants
7//--------------------------------------------------------------------------------------------------
8
9/// Memory-accounting charge in addition to each output payload.
10pub const EXEC_OUTPUT_EVENT_OVERHEAD: u32 = 256;
11
12//--------------------------------------------------------------------------------------------------
13// Types
14//--------------------------------------------------------------------------------------------------
15
16/// Effective policy shared by every execution in one sandbox.
17///
18/// The values are fixed defaults chosen by the runtime; a resumed memory snapshot keeps its
19/// captured policy. Connected clients discover the effective policy in Ready; execution
20/// requests cannot change it.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
22#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
23#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
24#[serde(default)]
25pub struct ExecLimits {
26    /// Maximum admitted executions, including exited streams with unread output.
27    pub max_executions: u32,
28    /// Maximum stdin bytes not yet delivered into the command's pipe.
29    pub input_limit: u32,
30    /// Maximum unconsumed stdout/stderr allowance, including per-message overhead.
31    pub output_limit: u32,
32    /// Maximum payload of one stdin message.
33    pub stdin_chunk_size: u32,
34    /// Maximum payload of one stdout or stderr message.
35    pub output_chunk_size: u32,
36}
37
38//--------------------------------------------------------------------------------------------------
39// Methods
40//--------------------------------------------------------------------------------------------------
41
42impl ExecLimits {
43    /// Reject policies whose chunks cannot make progress within their allowances.
44    pub fn validate(&self) -> Result<(), &'static str> {
45        // The protocol frame ceiling is 4 MiB; leave space for its envelope.
46        const MAX_CHUNK_SIZE: u32 = 4 * 1024 * 1024 - 1024;
47        if self.stdin_chunk_size > MAX_CHUNK_SIZE || self.output_chunk_size > MAX_CHUNK_SIZE {
48            return Err("execution chunk sizes must fit within the protocol frame ceiling");
49        }
50        if self.max_executions == 0 {
51            return Err("exec.max_executions must be positive");
52        }
53        if self.stdin_chunk_size == 0 || self.stdin_chunk_size > self.input_limit {
54            return Err("exec.stdin_chunk_size must be positive and fit within exec.input_limit");
55        }
56        let output_charge = self
57            .output_chunk_size
58            .checked_add(EXEC_OUTPUT_EVENT_OVERHEAD);
59        if self.output_chunk_size == 0 || output_charge.is_none_or(|n| n > self.output_limit) {
60            return Err(
61                "exec.output_chunk_size plus message overhead must fit within exec.output_limit",
62            );
63        }
64        Ok(())
65    }
66}
67
68//--------------------------------------------------------------------------------------------------
69// Trait Implementations
70//--------------------------------------------------------------------------------------------------
71
72impl Default for ExecLimits {
73    fn default() -> Self {
74        Self {
75            max_executions: 128,
76            input_limit: 64 * 1024,
77            output_limit: 1024 * 1024,
78            stdin_chunk_size: 16 * 1024,
79            output_chunk_size: 16 * 1024,
80        }
81    }
82}