mirror of
https://github.com/openai/codex.git
synced 2026-05-02 02:17:22 +00:00
Extract sandbox manager and transforms into codex-sandboxing (#15603)
Extract sandbox manager
This commit is contained in:
@@ -1,7 +1,17 @@
|
||||
pub mod landlock;
|
||||
pub mod macos_permissions;
|
||||
mod manager;
|
||||
pub mod policy_transforms;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub mod seatbelt;
|
||||
#[cfg(target_os = "macos")]
|
||||
mod seatbelt_permissions;
|
||||
|
||||
pub use manager::SandboxCommand;
|
||||
pub use manager::SandboxExecRequest;
|
||||
pub use manager::SandboxManager;
|
||||
pub use manager::SandboxTransformError;
|
||||
pub use manager::SandboxTransformRequest;
|
||||
pub use manager::SandboxType;
|
||||
pub use manager::SandboxablePreference;
|
||||
pub use manager::get_platform_sandbox;
|
||||
|
||||
276
codex-rs/sandboxing/src/manager.rs
Normal file
276
codex-rs/sandboxing/src/manager.rs
Normal file
@@ -0,0 +1,276 @@
|
||||
use crate::landlock::allow_network_for_proxy;
|
||||
use crate::landlock::create_linux_sandbox_command_args_for_policies;
|
||||
use crate::policy_transforms::EffectiveSandboxPermissions;
|
||||
use crate::policy_transforms::effective_file_system_sandbox_policy;
|
||||
use crate::policy_transforms::effective_network_sandbox_policy;
|
||||
use crate::policy_transforms::should_require_platform_sandbox;
|
||||
#[cfg(target_os = "macos")]
|
||||
use crate::seatbelt::MACOS_PATH_TO_SEATBELT_EXECUTABLE;
|
||||
#[cfg(target_os = "macos")]
|
||||
use crate::seatbelt::create_seatbelt_command_args_for_policies_with_extensions;
|
||||
use codex_network_proxy::NetworkProxy;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
#[cfg(target_os = "macos")]
|
||||
use codex_protocol::models::MacOsSeatbeltProfileExtensions;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::permissions::FileSystemSandboxPolicy;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum SandboxType {
|
||||
None,
|
||||
MacosSeatbelt,
|
||||
LinuxSeccomp,
|
||||
WindowsRestrictedToken,
|
||||
}
|
||||
|
||||
impl SandboxType {
|
||||
pub fn as_metric_tag(self) -> &'static str {
|
||||
match self {
|
||||
SandboxType::None => "none",
|
||||
SandboxType::MacosSeatbelt => "seatbelt",
|
||||
SandboxType::LinuxSeccomp => "seccomp",
|
||||
SandboxType::WindowsRestrictedToken => "windows_sandbox",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum SandboxablePreference {
|
||||
Auto,
|
||||
Require,
|
||||
Forbid,
|
||||
}
|
||||
|
||||
pub fn get_platform_sandbox(windows_sandbox_enabled: bool) -> Option<SandboxType> {
|
||||
if cfg!(target_os = "macos") {
|
||||
Some(SandboxType::MacosSeatbelt)
|
||||
} else if cfg!(target_os = "linux") {
|
||||
Some(SandboxType::LinuxSeccomp)
|
||||
} else if cfg!(target_os = "windows") {
|
||||
if windows_sandbox_enabled {
|
||||
Some(SandboxType::WindowsRestrictedToken)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SandboxCommand {
|
||||
pub program: String,
|
||||
pub args: Vec<String>,
|
||||
pub cwd: PathBuf,
|
||||
pub env: HashMap<String, String>,
|
||||
pub additional_permissions: Option<PermissionProfile>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SandboxExecRequest {
|
||||
pub command: Vec<String>,
|
||||
pub cwd: PathBuf,
|
||||
pub env: HashMap<String, String>,
|
||||
pub network: Option<NetworkProxy>,
|
||||
pub sandbox: SandboxType,
|
||||
pub windows_sandbox_level: WindowsSandboxLevel,
|
||||
pub windows_sandbox_private_desktop: bool,
|
||||
pub sandbox_policy: SandboxPolicy,
|
||||
pub file_system_sandbox_policy: FileSystemSandboxPolicy,
|
||||
pub network_sandbox_policy: NetworkSandboxPolicy,
|
||||
pub arg0: Option<String>,
|
||||
}
|
||||
|
||||
/// Bundled arguments for sandbox transformation.
|
||||
///
|
||||
/// This keeps call sites self-documenting when several fields are optional.
|
||||
pub struct SandboxTransformRequest<'a> {
|
||||
pub command: SandboxCommand,
|
||||
pub policy: &'a SandboxPolicy,
|
||||
pub file_system_policy: &'a FileSystemSandboxPolicy,
|
||||
pub network_policy: NetworkSandboxPolicy,
|
||||
pub sandbox: SandboxType,
|
||||
pub enforce_managed_network: bool,
|
||||
// TODO(viyatb): Evaluate switching this to Option<Arc<NetworkProxy>>
|
||||
// to make shared ownership explicit across runtime/sandbox plumbing.
|
||||
pub network: Option<&'a NetworkProxy>,
|
||||
pub sandbox_policy_cwd: &'a Path,
|
||||
#[cfg(target_os = "macos")]
|
||||
pub macos_seatbelt_profile_extensions: Option<&'a MacOsSeatbeltProfileExtensions>,
|
||||
pub codex_linux_sandbox_exe: Option<&'a PathBuf>,
|
||||
pub use_legacy_landlock: bool,
|
||||
pub windows_sandbox_level: WindowsSandboxLevel,
|
||||
pub windows_sandbox_private_desktop: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SandboxTransformError {
|
||||
MissingLinuxSandboxExecutable,
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
SeatbeltUnavailable,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SandboxTransformError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::MissingLinuxSandboxExecutable => {
|
||||
write!(f, "missing codex-linux-sandbox executable path")
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
Self::SeatbeltUnavailable => write!(f, "seatbelt sandbox is only available on macOS"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for SandboxTransformError {}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SandboxManager;
|
||||
|
||||
impl SandboxManager {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
pub fn select_initial(
|
||||
&self,
|
||||
file_system_policy: &FileSystemSandboxPolicy,
|
||||
network_policy: NetworkSandboxPolicy,
|
||||
pref: SandboxablePreference,
|
||||
windows_sandbox_level: WindowsSandboxLevel,
|
||||
has_managed_network_requirements: bool,
|
||||
) -> SandboxType {
|
||||
match pref {
|
||||
SandboxablePreference::Forbid => SandboxType::None,
|
||||
SandboxablePreference::Require => {
|
||||
get_platform_sandbox(windows_sandbox_level != WindowsSandboxLevel::Disabled)
|
||||
.unwrap_or(SandboxType::None)
|
||||
}
|
||||
SandboxablePreference::Auto => {
|
||||
if should_require_platform_sandbox(
|
||||
file_system_policy,
|
||||
network_policy,
|
||||
has_managed_network_requirements,
|
||||
) {
|
||||
get_platform_sandbox(windows_sandbox_level != WindowsSandboxLevel::Disabled)
|
||||
.unwrap_or(SandboxType::None)
|
||||
} else {
|
||||
SandboxType::None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transform(
|
||||
&self,
|
||||
request: SandboxTransformRequest<'_>,
|
||||
) -> Result<SandboxExecRequest, SandboxTransformError> {
|
||||
let SandboxTransformRequest {
|
||||
mut command,
|
||||
policy,
|
||||
file_system_policy,
|
||||
network_policy,
|
||||
sandbox,
|
||||
enforce_managed_network,
|
||||
network,
|
||||
sandbox_policy_cwd,
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions,
|
||||
codex_linux_sandbox_exe,
|
||||
use_legacy_landlock,
|
||||
windows_sandbox_level,
|
||||
windows_sandbox_private_desktop,
|
||||
} = request;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let macos_seatbelt_profile_extensions = None;
|
||||
let additional_permissions = command.additional_permissions.take();
|
||||
let EffectiveSandboxPermissions {
|
||||
sandbox_policy: effective_policy,
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: effective_macos_seatbelt_profile_extensions,
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
macos_seatbelt_profile_extensions: _,
|
||||
} = EffectiveSandboxPermissions::new(
|
||||
policy,
|
||||
macos_seatbelt_profile_extensions,
|
||||
additional_permissions.as_ref(),
|
||||
);
|
||||
let effective_file_system_policy = effective_file_system_sandbox_policy(
|
||||
file_system_policy,
|
||||
additional_permissions.as_ref(),
|
||||
);
|
||||
let effective_network_policy =
|
||||
effective_network_sandbox_policy(network_policy, additional_permissions.as_ref());
|
||||
let mut argv = Vec::with_capacity(1 + command.args.len());
|
||||
argv.push(command.program);
|
||||
argv.append(&mut command.args);
|
||||
|
||||
let (argv, arg0_override) = match sandbox {
|
||||
SandboxType::None => (argv, None),
|
||||
#[cfg(target_os = "macos")]
|
||||
SandboxType::MacosSeatbelt => {
|
||||
let mut args = create_seatbelt_command_args_for_policies_with_extensions(
|
||||
argv.clone(),
|
||||
&effective_file_system_policy,
|
||||
effective_network_policy,
|
||||
sandbox_policy_cwd,
|
||||
enforce_managed_network,
|
||||
network,
|
||||
effective_macos_seatbelt_profile_extensions.as_ref(),
|
||||
);
|
||||
let mut full_command = Vec::with_capacity(1 + args.len());
|
||||
full_command.push(MACOS_PATH_TO_SEATBELT_EXECUTABLE.to_string());
|
||||
full_command.append(&mut args);
|
||||
(full_command, None)
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
SandboxType::MacosSeatbelt => return Err(SandboxTransformError::SeatbeltUnavailable),
|
||||
SandboxType::LinuxSeccomp => {
|
||||
let exe = codex_linux_sandbox_exe
|
||||
.ok_or(SandboxTransformError::MissingLinuxSandboxExecutable)?;
|
||||
let allow_proxy_network = allow_network_for_proxy(enforce_managed_network);
|
||||
let mut args = create_linux_sandbox_command_args_for_policies(
|
||||
argv.clone(),
|
||||
command.cwd.as_path(),
|
||||
&effective_policy,
|
||||
&effective_file_system_policy,
|
||||
effective_network_policy,
|
||||
sandbox_policy_cwd,
|
||||
use_legacy_landlock,
|
||||
allow_proxy_network,
|
||||
);
|
||||
let mut full_command = Vec::with_capacity(1 + args.len());
|
||||
full_command.push(exe.to_string_lossy().to_string());
|
||||
full_command.append(&mut args);
|
||||
(full_command, Some("codex-linux-sandbox".to_string()))
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
SandboxType::WindowsRestrictedToken => (argv, None),
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
SandboxType::WindowsRestrictedToken => (argv, None),
|
||||
};
|
||||
|
||||
Ok(SandboxExecRequest {
|
||||
command: argv,
|
||||
cwd: command.cwd,
|
||||
env: command.env,
|
||||
network: network.cloned(),
|
||||
sandbox,
|
||||
windows_sandbox_level,
|
||||
windows_sandbox_private_desktop,
|
||||
sandbox_policy: effective_policy,
|
||||
file_system_sandbox_policy: effective_file_system_policy,
|
||||
network_sandbox_policy: effective_network_policy,
|
||||
arg0: arg0_override,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "manager_tests.rs"]
|
||||
mod tests;
|
||||
251
codex-rs/sandboxing/src/manager_tests.rs
Normal file
251
codex-rs/sandboxing/src/manager_tests.rs
Normal file
@@ -0,0 +1,251 @@
|
||||
use super::SandboxCommand;
|
||||
use super::SandboxManager;
|
||||
use super::SandboxTransformRequest;
|
||||
use super::SandboxType;
|
||||
use super::SandboxablePreference;
|
||||
use super::get_platform_sandbox;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::FileSystemPermissions;
|
||||
use codex_protocol::models::NetworkPermissions;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::permissions::FileSystemAccessMode;
|
||||
use codex_protocol::permissions::FileSystemPath;
|
||||
use codex_protocol::permissions::FileSystemSandboxEntry;
|
||||
use codex_protocol::permissions::FileSystemSandboxPolicy;
|
||||
use codex_protocol::permissions::FileSystemSpecialPath;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::NetworkAccess;
|
||||
use codex_protocol::protocol::ReadOnlyAccess;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use dunce::canonicalize;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::collections::HashMap;
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[test]
|
||||
fn danger_full_access_defaults_to_no_sandbox_without_network_requirements() {
|
||||
let manager = SandboxManager::new();
|
||||
let sandbox = manager.select_initial(
|
||||
&FileSystemSandboxPolicy::unrestricted(),
|
||||
NetworkSandboxPolicy::Enabled,
|
||||
SandboxablePreference::Auto,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
false,
|
||||
);
|
||||
assert_eq!(sandbox, SandboxType::None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn danger_full_access_uses_platform_sandbox_with_network_requirements() {
|
||||
let manager = SandboxManager::new();
|
||||
let expected = get_platform_sandbox(false).unwrap_or(SandboxType::None);
|
||||
let sandbox = manager.select_initial(
|
||||
&FileSystemSandboxPolicy::unrestricted(),
|
||||
NetworkSandboxPolicy::Enabled,
|
||||
SandboxablePreference::Auto,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
true,
|
||||
);
|
||||
assert_eq!(sandbox, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn restricted_file_system_uses_platform_sandbox_without_managed_network() {
|
||||
let manager = SandboxManager::new();
|
||||
let expected = get_platform_sandbox(false).unwrap_or(SandboxType::None);
|
||||
let sandbox = manager.select_initial(
|
||||
&FileSystemSandboxPolicy::restricted(vec![FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::Root,
|
||||
},
|
||||
access: FileSystemAccessMode::Read,
|
||||
}]),
|
||||
NetworkSandboxPolicy::Enabled,
|
||||
SandboxablePreference::Auto,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
false,
|
||||
);
|
||||
assert_eq!(sandbox, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transform_preserves_unrestricted_file_system_policy_for_restricted_network() {
|
||||
let manager = SandboxManager::new();
|
||||
let cwd = std::env::current_dir().expect("current dir");
|
||||
let exec_request = manager
|
||||
.transform(SandboxTransformRequest {
|
||||
command: SandboxCommand {
|
||||
program: "true".to_string(),
|
||||
args: Vec::new(),
|
||||
cwd: cwd.clone(),
|
||||
env: HashMap::new(),
|
||||
additional_permissions: None,
|
||||
},
|
||||
policy: &SandboxPolicy::ExternalSandbox {
|
||||
network_access: NetworkAccess::Restricted,
|
||||
},
|
||||
file_system_policy: &FileSystemSandboxPolicy::unrestricted(),
|
||||
network_policy: NetworkSandboxPolicy::Restricted,
|
||||
sandbox: SandboxType::None,
|
||||
enforce_managed_network: false,
|
||||
network: None,
|
||||
sandbox_policy_cwd: cwd.as_path(),
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_legacy_landlock: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: false,
|
||||
})
|
||||
.expect("transform");
|
||||
|
||||
assert_eq!(
|
||||
exec_request.file_system_sandbox_policy,
|
||||
FileSystemSandboxPolicy::unrestricted()
|
||||
);
|
||||
assert_eq!(
|
||||
exec_request.network_sandbox_policy,
|
||||
NetworkSandboxPolicy::Restricted
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transform_additional_permissions_enable_network_for_external_sandbox() {
|
||||
let manager = SandboxManager::new();
|
||||
let cwd = std::env::current_dir().expect("current dir");
|
||||
let temp_dir = TempDir::new().expect("create temp dir");
|
||||
let path = AbsolutePathBuf::from_absolute_path(
|
||||
canonicalize(temp_dir.path()).expect("canonicalize temp dir"),
|
||||
)
|
||||
.expect("absolute temp dir");
|
||||
let exec_request = manager
|
||||
.transform(SandboxTransformRequest {
|
||||
command: SandboxCommand {
|
||||
program: "true".to_string(),
|
||||
args: Vec::new(),
|
||||
cwd: cwd.clone(),
|
||||
env: HashMap::new(),
|
||||
additional_permissions: Some(PermissionProfile {
|
||||
network: Some(NetworkPermissions {
|
||||
enabled: Some(true),
|
||||
}),
|
||||
file_system: Some(FileSystemPermissions {
|
||||
read: Some(vec![path]),
|
||||
write: Some(Vec::new()),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
},
|
||||
policy: &SandboxPolicy::ExternalSandbox {
|
||||
network_access: NetworkAccess::Restricted,
|
||||
},
|
||||
file_system_policy: &FileSystemSandboxPolicy::unrestricted(),
|
||||
network_policy: NetworkSandboxPolicy::Restricted,
|
||||
sandbox: SandboxType::None,
|
||||
enforce_managed_network: false,
|
||||
network: None,
|
||||
sandbox_policy_cwd: cwd.as_path(),
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_legacy_landlock: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: false,
|
||||
})
|
||||
.expect("transform");
|
||||
|
||||
assert_eq!(
|
||||
exec_request.sandbox_policy,
|
||||
SandboxPolicy::ExternalSandbox {
|
||||
network_access: NetworkAccess::Enabled,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
exec_request.network_sandbox_policy,
|
||||
NetworkSandboxPolicy::Enabled
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transform_additional_permissions_preserves_denied_entries() {
|
||||
let manager = SandboxManager::new();
|
||||
let cwd = std::env::current_dir().expect("current dir");
|
||||
let temp_dir = TempDir::new().expect("create temp dir");
|
||||
let workspace_root = AbsolutePathBuf::from_absolute_path(
|
||||
canonicalize(temp_dir.path()).expect("canonicalize temp dir"),
|
||||
)
|
||||
.expect("absolute temp dir");
|
||||
let allowed_path = workspace_root.join("allowed").expect("allowed path");
|
||||
let denied_path = workspace_root.join("denied").expect("denied path");
|
||||
let exec_request = manager
|
||||
.transform(SandboxTransformRequest {
|
||||
command: SandboxCommand {
|
||||
program: "true".to_string(),
|
||||
args: Vec::new(),
|
||||
cwd: cwd.clone(),
|
||||
env: HashMap::new(),
|
||||
additional_permissions: Some(PermissionProfile {
|
||||
file_system: Some(FileSystemPermissions {
|
||||
read: None,
|
||||
write: Some(vec![allowed_path.clone()]),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
},
|
||||
policy: &SandboxPolicy::ReadOnly {
|
||||
access: ReadOnlyAccess::FullAccess,
|
||||
network_access: false,
|
||||
},
|
||||
file_system_policy: &FileSystemSandboxPolicy::restricted(vec![
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::Root,
|
||||
},
|
||||
access: FileSystemAccessMode::Read,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path {
|
||||
path: denied_path.clone(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
},
|
||||
]),
|
||||
network_policy: NetworkSandboxPolicy::Restricted,
|
||||
sandbox: SandboxType::None,
|
||||
enforce_managed_network: false,
|
||||
network: None,
|
||||
sandbox_policy_cwd: cwd.as_path(),
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_legacy_landlock: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: false,
|
||||
})
|
||||
.expect("transform");
|
||||
|
||||
assert_eq!(
|
||||
exec_request.file_system_sandbox_policy,
|
||||
FileSystemSandboxPolicy::restricted(vec![
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::Root,
|
||||
},
|
||||
access: FileSystemAccessMode::Read,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: denied_path },
|
||||
access: FileSystemAccessMode::None,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: allowed_path },
|
||||
access: FileSystemAccessMode::Write,
|
||||
},
|
||||
])
|
||||
);
|
||||
assert_eq!(
|
||||
exec_request.network_sandbox_policy,
|
||||
NetworkSandboxPolicy::Restricted
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user