sandbox_runtime/sandbox/
mod.rs

1//! Platform-specific sandbox implementations.
2
3#[cfg(target_os = "macos")]
4pub mod macos;
5
6#[cfg(target_os = "linux")]
7pub mod linux;
8
9use crate::config::SandboxRuntimeConfig;
10use crate::error::SandboxError;
11use crate::utils::Platform;
12
13/// Detailed status of sandbox dependencies.
14#[derive(Debug, Clone, Default)]
15pub struct LinuxDependencyStatus {
16    pub has_bwrap: bool,
17    pub has_socat: bool,
18    pub has_seccomp_bpf: bool,
19    pub has_seccomp_apply: bool,
20}
21
22/// Result of checking sandbox dependencies.
23#[derive(Debug, Clone, Default)]
24pub struct SandboxDependencyCheck {
25    /// Errors that prevent the sandbox from running.
26    pub errors: Vec<String>,
27    /// Warnings about degraded functionality.
28    pub warnings: Vec<String>,
29}
30
31impl SandboxDependencyCheck {
32    /// Returns true if there are no errors.
33    pub fn is_ok(&self) -> bool {
34        self.errors.is_empty()
35    }
36
37    /// Convert to Result, returning error if there are any errors.
38    pub fn into_result(self) -> Result<Self, SandboxError> {
39        if self.errors.is_empty() {
40            Ok(self)
41        } else {
42            Err(SandboxError::MissingDependency(self.errors.join(", ")))
43        }
44    }
45}
46
47/// Get detailed status of Linux sandbox dependencies.
48#[cfg(target_os = "linux")]
49pub fn get_linux_dependency_status(
50    seccomp_config: Option<&crate::config::SeccompConfig>,
51) -> LinuxDependencyStatus {
52    LinuxDependencyStatus {
53        has_bwrap: linux::check_bwrap(),
54        has_socat: linux::check_socat(),
55        has_seccomp_bpf: linux::get_bpf_path(seccomp_config).is_ok(),
56        has_seccomp_apply: linux::get_apply_seccomp_path(seccomp_config).is_ok(),
57    }
58}
59
60/// Check sandbox dependencies and return structured result.
61#[cfg(target_os = "linux")]
62pub fn check_linux_dependencies(
63    seccomp_config: Option<&crate::config::SeccompConfig>,
64) -> SandboxDependencyCheck {
65    let mut result = SandboxDependencyCheck::default();
66
67    if !linux::check_bwrap() {
68        result.errors.push("bubblewrap (bwrap) not installed".to_string());
69    }
70    if !linux::check_socat() {
71        result.errors.push("socat not installed".to_string());
72    }
73
74    let has_bpf = linux::get_bpf_path(seccomp_config).is_ok();
75    let has_apply = linux::get_apply_seccomp_path(seccomp_config).is_ok();
76    if !has_bpf || !has_apply {
77        result.warnings.push(
78            "seccomp not available - unix socket access not restricted".to_string(),
79        );
80    }
81
82    result
83}
84
85/// Check if sandboxing dependencies are available for the current platform.
86/// Returns a structured result with errors and warnings.
87pub fn check_dependencies_detailed(
88    platform: Platform,
89    #[cfg_attr(not(target_os = "linux"), allow(unused_variables))]
90    seccomp_config: Option<&crate::config::SeccompConfig>,
91) -> SandboxDependencyCheck {
92    match platform {
93        Platform::MacOS => {
94            // sandbox-exec is built into macOS
95            SandboxDependencyCheck::default()
96        }
97        Platform::Linux => {
98            #[cfg(target_os = "linux")]
99            {
100                check_linux_dependencies(seccomp_config)
101            }
102            #[cfg(not(target_os = "linux"))]
103            {
104                SandboxDependencyCheck {
105                    errors: vec!["Linux sandbox code not compiled on this platform".to_string()],
106                    warnings: vec![],
107                }
108            }
109        }
110    }
111}
112
113/// Check if sandboxing dependencies are available for the current platform.
114/// Legacy function that returns Result for backward compatibility.
115pub fn check_dependencies(platform: Platform) -> Result<(), SandboxError> {
116    check_dependencies_detailed(platform, None).into_result().map(|_| ())
117}
118
119/// Wrap a command with platform-specific sandboxing.
120pub async fn wrap_command(
121    command: &str,
122    config: &SandboxRuntimeConfig,
123    platform: Platform,
124    http_proxy_port: Option<u16>,
125    socks_proxy_port: Option<u16>,
126    #[cfg(target_os = "linux")] http_socket_path: Option<&str>,
127    #[cfg(target_os = "linux")] socks_socket_path: Option<&str>,
128    shell: Option<&str>,
129    enable_log_monitor: bool,
130) -> Result<WrapResult, SandboxError> {
131    match platform {
132        Platform::MacOS => {
133            #[cfg(target_os = "macos")]
134            {
135                let (wrapped, log_tag) = macos::wrap_command(
136                    command,
137                    config,
138                    http_proxy_port,
139                    socks_proxy_port,
140                    shell,
141                    enable_log_monitor,
142                )?;
143                Ok(WrapResult {
144                    command: wrapped,
145                    log_tag,
146                    warnings: vec![],
147                })
148            }
149            #[cfg(not(target_os = "macos"))]
150            {
151                Err(SandboxError::UnsupportedPlatform(
152                    "macOS sandbox code not compiled on this platform".to_string(),
153                ))
154            }
155        }
156        Platform::Linux => {
157            #[cfg(target_os = "linux")]
158            {
159                let cwd = std::env::current_dir()?;
160                let (wrapped, warnings) = linux::generate_bwrap_command(
161                    command,
162                    config,
163                    &cwd,
164                    http_socket_path,
165                    socks_socket_path,
166                    http_proxy_port.unwrap_or(3128),
167                    socks_proxy_port.unwrap_or(1080),
168                    shell,
169                )?;
170                Ok(WrapResult {
171                    command: wrapped,
172                    log_tag: None,
173                    warnings,
174                })
175            }
176            #[cfg(not(target_os = "linux"))]
177            {
178                Err(SandboxError::UnsupportedPlatform(
179                    "Linux sandbox code not compiled on this platform".to_string(),
180                ))
181            }
182        }
183    }
184}
185
186/// Result of wrapping a command with sandbox.
187#[derive(Debug)]
188pub struct WrapResult {
189    /// The wrapped command string.
190    pub command: String,
191    /// Log tag for violation monitoring (macOS only).
192    pub log_tag: Option<String>,
193    /// Warnings generated during wrapping.
194    pub warnings: Vec<String>,
195}