Skip to main content

ai_sandbox/
lib.rs

1//! AI Sandbox - Cross-platform AI tool sandbox security
2//!
3//! A comprehensive sandbox library supporting multiple platforms:
4//! - Linux: Bubblewrap + Seccomp + Landlock
5//! - macOS: Seatbelt (sandbox-exec)
6//! - Windows: Restricted Token
7//! - FreeBSD: Capsicum
8//! - OpenBSD: pledge
9//!
10//! # Unified API
11//!
12//! This crate provides a unified API that works across all supported platforms.
13//! Users do not need to write platform-specific code.
14//!
15//! ## Quick Start
16//!
17//! ```ignore
18//! use ai_sandbox::{SandboxManager, SandboxPolicy, SandboxCommand};
19//! use std::collections::HashMap;
20//! use std::ffi::OsString;
21//! use std::path::PathBuf;
22//!
23//! // Create sandbox manager - automatically detects platform
24//! let manager = SandboxManager::new();
25//!
26//! // Define your command
27//! let command = SandboxCommand {
28//!     program: OsString::from("ls"),
29//!     args: vec!["-la".to_string()],
30//!     cwd: PathBuf::from("/tmp"),
31//!     env: HashMap::new(),
32//! };
33//!
34//! // Define sandbox policy
35//! let policy = SandboxPolicy::default();
36//!
37//! // Create sandboxed execution request
38//! let request = manager.create_exec_request(command, policy).unwrap();
39//! ```
40
41pub mod execpolicy;
42pub mod linux_sandbox;
43pub mod process_hardening;
44pub mod sandboxing;
45pub mod windows_sandbox;
46
47// Re-export SandboxPolicyExt for external use
48pub use sandboxing::SandboxPolicyExt;
49
50// ============================================================================
51// Core API - 这些是用户主要使用的接口
52// ============================================================================
53
54// 沙箱管理
55pub use sandboxing::{
56    get_platform_sandbox, FileSystemSandboxPolicy, NetworkSandboxPolicy, SandboxCommand,
57    SandboxExecRequest, SandboxManager, SandboxPolicy, SandboxTransformError, SandboxType,
58    SandboxablePreference,
59};
60// 进程加固
61pub use process_hardening::pre_main_hardening;
62
63// 执行策略
64pub use execpolicy::{
65    parse_policy, Decision, NetworkRule, Policy, PrefixRule, RuleMatch, RuleType,
66};
67
68// ============================================================================
69// Extended API - 高级用户可能需要的接口
70// ============================================================================
71
72// Linux 特定功能 - 所有平台都可调用,非 Linux 返回默认值
73#[allow(unused_imports)]
74pub use linux_sandbox::{
75    create_linux_sandbox_command_args_for_policies, create_pledge_promises_from_policy,
76    execute_with_capsicum, execute_with_pledge, find_system_bwrap_in_path, get_landlock_version,
77    is_landlock_available, system_bwrap_warning, CapsicumLevel, PledgePromises,
78};
79
80// Windows 特定功能 - 所有平台都可调用,非 Windows 返回默认值
81#[allow(unused_imports)]
82pub use windows_sandbox::{
83    create_windows_sandbox_args, is_windows_sandbox_available, WindowsSandboxLevel,
84};
85
86#[cfg(test)]
87mod tests {
88    use crate::{get_platform_sandbox, SandboxType};
89
90    #[test]
91    fn test_platform_detection() {
92        // On Windows, sandbox requires windows_sandbox_enabled = true
93        // Use true to ensure test passes on all platforms
94        #[cfg(target_os = "windows")]
95        let sandbox = get_platform_sandbox(true);
96        #[cfg(not(target_os = "windows"))]
97        let sandbox = get_platform_sandbox(false);
98
99        #[cfg(any(
100            target_os = "linux",
101            target_os = "macos",
102            target_os = "windows",
103            target_os = "freebsd",
104            target_os = "openbsd"
105        ))]
106        {
107            assert!(sandbox.is_some());
108        }
109        #[cfg(not(any(
110            target_os = "linux",
111            target_os = "macos",
112            target_os = "windows",
113            target_os = "freebsd",
114            target_os = "openbsd"
115        )))]
116        {
117            assert!(sandbox.is_none());
118        }
119    }
120
121    #[test]
122    #[cfg(target_os = "macos")]
123    fn test_sandbox_manager_create_request() {
124        use crate::{SandboxCommand, SandboxManager, SandboxPolicy};
125        use std::collections::HashMap;
126        use std::ffi::OsString;
127        use std::path::PathBuf;
128
129        let manager = SandboxManager::new();
130        let command = SandboxCommand {
131            program: OsString::from("ls"),
132            args: vec!["-la".to_string()],
133            cwd: PathBuf::from("/tmp"),
134            env: HashMap::new(),
135        };
136
137        let result = manager.create_exec_request(command, SandboxPolicy::default());
138        assert!(result.is_ok());
139
140        let request = result.unwrap();
141        assert!(!request.command.is_empty());
142    }
143
144    #[test]
145    #[cfg(not(target_os = "macos"))]
146    fn test_sandbox_manager_create_request() {
147        // Skip test on non-macOS platforms as it requires platform-specific sandbox executable
148    }
149
150    #[test]
151    #[cfg(target_os = "macos")]
152    fn test_readonly_policy() {
153        use crate::{SandboxCommand, SandboxManager, SandboxPolicy};
154        use std::collections::HashMap;
155        use std::ffi::OsString;
156        use std::path::PathBuf;
157
158        let policy = SandboxPolicy::ReadOnly {
159            file_system: crate::FileSystemSandboxPolicy::ReadOnly,
160            network_access: crate::NetworkSandboxPolicy::NoAccess,
161        };
162
163        let manager = SandboxManager::new();
164        let command = SandboxCommand {
165            program: OsString::from("cat"),
166            args: vec!["/etc/passwd".to_string()],
167            cwd: PathBuf::from("/tmp"),
168            env: HashMap::new(),
169        };
170
171        let result = manager.create_exec_request(command, policy);
172        assert!(result.is_ok());
173    }
174
175    #[test]
176    #[cfg(not(target_os = "macos"))]
177    fn test_readonly_policy() {
178        // Skip test on non-macOS platforms as it requires platform-specific sandbox executable
179    }
180
181    #[test]
182    #[cfg(target_os = "macos")]
183    fn test_workspace_policy() {
184        use crate::{SandboxCommand, SandboxManager, SandboxPolicy};
185        use std::collections::HashMap;
186        use std::ffi::OsString;
187        use std::path::PathBuf;
188
189        let policy = SandboxPolicy::WorkspaceWrite {
190            writable_roots: vec![PathBuf::from("/tmp")],
191            network_access: crate::NetworkSandboxPolicy::Localhost,
192        };
193
194        let manager = SandboxManager::new();
195        let command = SandboxCommand {
196            program: OsString::from("touch"),
197            args: vec!["test.txt".to_string()],
198            cwd: PathBuf::from("/tmp"),
199            env: HashMap::new(),
200        };
201
202        let result = manager.create_exec_request(command, policy);
203        assert!(result.is_ok());
204    }
205
206    #[test]
207    #[cfg(not(target_os = "macos"))]
208    fn test_workspace_policy() {
209        // Skip test on non-macOS platforms as it requires platform-specific sandbox executable
210    }
211
212    #[test]
213    fn test_sandbox_type_names() {
214        assert_eq!(SandboxType::None.as_metric_tag(), "none");
215        assert_eq!(SandboxType::MacosSeatbelt.as_metric_tag(), "seatbelt");
216        assert_eq!(SandboxType::LinuxSeccomp.as_metric_tag(), "seccomp");
217        assert_eq!(
218            SandboxType::WindowsRestrictedToken.as_metric_tag(),
219            "windows_sandbox"
220        );
221        assert_eq!(SandboxType::FreeBSDCapsicum.as_metric_tag(), "capsicum");
222        assert_eq!(SandboxType::OpenBSDPledge.as_metric_tag(), "pledge");
223    }
224}