Skip to main content

orchestrator_config/config/
execution_profile.rs

1use serde::{Deserialize, Serialize};
2
3/// Selects whether a step runs directly on the host or inside a sandbox.
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
5#[serde(rename_all = "snake_case")]
6pub enum ExecutionProfileMode {
7    /// Run commands with the ambient host execution environment.
8    #[default]
9    Host,
10    /// Run commands through the configured sandbox executor.
11    Sandbox,
12}
13
14/// Filesystem access mode enforced for an execution profile.
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
16#[serde(rename_all = "snake_case")]
17pub enum ExecutionFsMode {
18    /// Reuse the caller's default filesystem permissions.
19    #[default]
20    Inherit,
21    /// Mount the workspace as read-only.
22    WorkspaceReadonly,
23    /// Grant read-write access only to explicit workspace-scoped paths.
24    WorkspaceRwScoped,
25}
26
27/// Network access mode enforced for an execution profile.
28#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
29#[serde(rename_all = "snake_case")]
30pub enum ExecutionNetworkMode {
31    /// Reuse the caller's default network policy.
32    #[default]
33    Inherit,
34    /// Block outbound network access.
35    Deny,
36    /// Permit outbound access only to the configured allowlist.
37    Allowlist,
38}
39
40/// Resource and isolation limits applied to step execution.
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
42pub struct ExecutionProfileConfig {
43    /// Chooses the underlying execution environment.
44    #[serde(default)]
45    pub mode: ExecutionProfileMode,
46    /// Defines the filesystem visibility granted to the step.
47    #[serde(default)]
48    pub fs_mode: ExecutionFsMode,
49    /// Additional writable paths when `fs_mode` uses scoped write access.
50    #[serde(default, skip_serializing_if = "Vec::is_empty")]
51    pub writable_paths: Vec<String>,
52    /// Defines the network reachability granted to the step.
53    #[serde(default)]
54    pub network_mode: ExecutionNetworkMode,
55    /// Explicit network destinations allowed when `network_mode` is `Allowlist`.
56    #[serde(default, skip_serializing_if = "Vec::is_empty")]
57    pub network_allowlist: Vec<String>,
58    /// Maximum resident memory in MiB.
59    #[serde(default, skip_serializing_if = "Option::is_none")]
60    pub max_memory_mb: Option<u64>,
61    /// Maximum accumulated CPU time in seconds.
62    #[serde(default, skip_serializing_if = "Option::is_none")]
63    pub max_cpu_seconds: Option<u64>,
64    /// Maximum number of child processes.
65    #[serde(default, skip_serializing_if = "Option::is_none")]
66    pub max_processes: Option<u64>,
67    /// Maximum number of open file descriptors.
68    #[serde(default, skip_serializing_if = "Option::is_none")]
69    pub max_open_files: Option<u64>,
70}
71
72impl Default for ExecutionProfileConfig {
73    fn default() -> Self {
74        Self {
75            mode: ExecutionProfileMode::Host,
76            fs_mode: ExecutionFsMode::Inherit,
77            writable_paths: Vec::new(),
78            network_mode: ExecutionNetworkMode::Inherit,
79            network_allowlist: Vec::new(),
80            max_memory_mb: None,
81            max_cpu_seconds: None,
82            max_processes: None,
83            max_open_files: None,
84        }
85    }
86}
87
88impl ExecutionProfileConfig {
89    /// Returns the implicit host profile used when a workflow does not specify one.
90    ///
91    /// # Examples
92    ///
93    /// ```rust
94    /// use orchestrator_config::config::{ExecutionProfileConfig, ExecutionProfileMode};
95    ///
96    /// let profile = ExecutionProfileConfig::implicit_host();
97    /// assert_eq!(profile.mode, ExecutionProfileMode::Host);
98    /// ```
99    pub fn implicit_host() -> Self {
100        Self::default()
101    }
102}