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