mirror of
https://github.com/openai/codex.git
synced 2026-11-03 16:23:51 +00:00
Support Unix socket allowlists in macOS sandbox (#17654)
## Changes Allows sandboxes to restrict overall network access while granting access to specific unix sockets on mac. ## Details - `codex sandbox macos`: adds a repeatable `--allow-unix-socket` option. - `codex-sandboxing`: threads explicit Unix socket roots into the macOS Seatbelt profile generation. - Preserves restricted network behavior when only Unix socket IPC is requested, and preserves full network behavior when full network is already enabled. ## Verification - `cargo test -p codex-cli -p codex-sandboxing` - `cargo build -p codex-cli --bin codex` - verified that `codex sandbox macos --allow-unix-socket /tmp/test.sock -- test-client` grants access as expected
This commit is contained in:
1 parent
42528a905d
commit
2e1003728c
8 files changed
+328
-96
No files matched your search
@@ -9,10 +9,6 @@ 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;
|
||||
use codex_network_proxy::NetworkProxy;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
@@ -208,14 +204,19 @@ impl SandboxManager {
|
||||
SandboxType::None => (os_argv_to_strings(argv), None),
|
||||
#[cfg(target_os = "macos")]
|
||||
SandboxType::MacosSeatbelt => {
|
||||
let mut args = create_seatbelt_command_args_for_policies(
|
||||
os_argv_to_strings(argv),
|
||||
&effective_file_system_policy,
|
||||
effective_network_policy,
|
||||
use crate::seatbelt::CreateSeatbeltCommandArgsParams;
|
||||
use crate::seatbelt::MACOS_PATH_TO_SEATBELT_EXECUTABLE;
|
||||
use crate::seatbelt::create_seatbelt_command_args;
|
||||
|
||||
let mut args = create_seatbelt_command_args(CreateSeatbeltCommandArgsParams {
|
||||
command: os_argv_to_strings(argv),
|
||||
file_system_sandbox_policy: &effective_file_system_policy,
|
||||
network_sandbox_policy: effective_network_policy,
|
||||
sandbox_policy_cwd,
|
||||
enforce_managed_network,
|
||||
network,
|
||||
);
|
||||
extra_allow_unix_sockets: &[],
|
||||
});
|
||||
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);
|
||||
|
||||
@@ -100,41 +100,54 @@ struct UnixSocketPathParam {
|
||||
path: AbsolutePathBuf,
|
||||
}
|
||||
|
||||
fn proxy_policy_inputs(network: Option<&NetworkProxy>) -> ProxyPolicyInputs {
|
||||
if let Some(network) = network {
|
||||
let mut env = HashMap::new();
|
||||
network.apply_to_env(&mut env);
|
||||
let unix_domain_socket_policy = if network.dangerously_allow_all_unix_sockets() {
|
||||
UnixDomainSocketPolicy::AllowAll
|
||||
} else {
|
||||
let allowed = network
|
||||
.allow_unix_sockets()
|
||||
.iter()
|
||||
.filter_map(
|
||||
|socket_path| match normalize_path_for_sandbox(Path::new(socket_path)) {
|
||||
Some(path) => Some((path.to_string_lossy().to_string(), path)),
|
||||
None => {
|
||||
warn!(
|
||||
"ignoring network.allow_unix_sockets entry because it could not be normalized: {socket_path}"
|
||||
);
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
.collect::<BTreeMap<_, _>>()
|
||||
.into_values()
|
||||
.collect();
|
||||
UnixDomainSocketPolicy::Restricted { allowed }
|
||||
};
|
||||
return ProxyPolicyInputs {
|
||||
ports: proxy_loopback_ports_from_env(&env),
|
||||
has_proxy_config: has_proxy_url_env_vars(&env),
|
||||
allow_local_binding: network.allow_local_binding(),
|
||||
unix_domain_socket_policy,
|
||||
};
|
||||
}
|
||||
fn proxy_policy_inputs(
|
||||
network: Option<&NetworkProxy>,
|
||||
extra_allow_unix_sockets: &[AbsolutePathBuf],
|
||||
) -> ProxyPolicyInputs {
|
||||
let extra_allowed = extra_allow_unix_sockets
|
||||
.iter()
|
||||
.filter_map(|socket_path| normalize_path_for_sandbox(socket_path.as_path()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
ProxyPolicyInputs::default()
|
||||
match network {
|
||||
Some(network) => {
|
||||
let mut env = HashMap::new();
|
||||
network.apply_to_env(&mut env);
|
||||
let unix_domain_socket_policy = if network.dangerously_allow_all_unix_sockets() {
|
||||
UnixDomainSocketPolicy::AllowAll
|
||||
} else {
|
||||
let mut allowed = network
|
||||
.allow_unix_sockets()
|
||||
.iter()
|
||||
.filter_map(|socket_path| {
|
||||
match normalize_path_for_sandbox(Path::new(socket_path)) {
|
||||
Some(path) => Some(path),
|
||||
None => {
|
||||
warn!(
|
||||
"ignoring network.allow_unix_sockets entry because it could not be normalized: {socket_path}"
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
allowed.extend(extra_allowed);
|
||||
UnixDomainSocketPolicy::Restricted { allowed }
|
||||
};
|
||||
ProxyPolicyInputs {
|
||||
ports: proxy_loopback_ports_from_env(&env),
|
||||
has_proxy_config: has_proxy_url_env_vars(&env),
|
||||
allow_local_binding: network.allow_local_binding(),
|
||||
unix_domain_socket_policy,
|
||||
}
|
||||
}
|
||||
None => ProxyPolicyInputs {
|
||||
unix_domain_socket_policy: UnixDomainSocketPolicy::Restricted {
|
||||
allowed: extra_allowed,
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_path_for_sandbox(path: &Path) -> Option<AbsolutePathBuf> {
|
||||
@@ -244,8 +257,14 @@ fn dynamic_network_policy_for_network(
|
||||
enforce_managed_network: bool,
|
||||
proxy: &ProxyPolicyInputs,
|
||||
) -> String {
|
||||
let should_use_restricted_network_policy =
|
||||
!proxy.ports.is_empty() || proxy.has_proxy_config || enforce_managed_network;
|
||||
let has_some_unix_socket_access = match &proxy.unix_domain_socket_policy {
|
||||
UnixDomainSocketPolicy::AllowAll => true,
|
||||
UnixDomainSocketPolicy::Restricted { allowed } => !allowed.is_empty(),
|
||||
};
|
||||
let should_use_restricted_network_policy = !proxy.ports.is_empty()
|
||||
|| proxy.has_proxy_config
|
||||
|| enforce_managed_network
|
||||
|| (!network_policy.is_enabled() && has_some_unix_socket_access);
|
||||
if should_use_restricted_network_policy {
|
||||
let mut policy = String::new();
|
||||
if proxy.allow_local_binding {
|
||||
@@ -285,9 +304,13 @@ fn dynamic_network_policy_for_network(
|
||||
|
||||
if network_policy.is_enabled() {
|
||||
// No proxy env is configured: retain the existing full-network behavior.
|
||||
format!(
|
||||
"(allow network-outbound)\n(allow network-inbound)\n{MACOS_SEATBELT_NETWORK_POLICY}"
|
||||
)
|
||||
let mut policy = String::from("(allow network-outbound)\n(allow network-inbound)\n");
|
||||
let unix_socket_policy = unix_socket_policy(proxy);
|
||||
if !unix_socket_policy.is_empty() {
|
||||
policy.push_str("; allow unix domain sockets for local IPC\n");
|
||||
policy.push_str(&unix_socket_policy);
|
||||
}
|
||||
format!("{policy}{MACOS_SEATBELT_NETWORK_POLICY}")
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
@@ -357,31 +380,48 @@ fn build_seatbelt_access_policy(
|
||||
}
|
||||
|
||||
#[cfg_attr(not(test), allow(dead_code))]
|
||||
fn create_seatbelt_command_args(
|
||||
fn create_seatbelt_command_args_for_legacy_policy(
|
||||
command: Vec<String>,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
sandbox_policy_cwd: &Path,
|
||||
enforce_managed_network: bool,
|
||||
network: Option<&NetworkProxy>,
|
||||
) -> Vec<String> {
|
||||
create_seatbelt_command_args_for_policies(
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(sandbox_policy, sandbox_policy_cwd);
|
||||
create_seatbelt_command_args(CreateSeatbeltCommandArgsParams {
|
||||
command,
|
||||
&FileSystemSandboxPolicy::from_legacy_sandbox_policy(sandbox_policy, sandbox_policy_cwd),
|
||||
NetworkSandboxPolicy::from(sandbox_policy),
|
||||
file_system_sandbox_policy: &file_system_sandbox_policy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy::from(sandbox_policy),
|
||||
sandbox_policy_cwd,
|
||||
enforce_managed_network,
|
||||
network,
|
||||
)
|
||||
extra_allow_unix_sockets: &[],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_seatbelt_command_args_for_policies(
|
||||
command: Vec<String>,
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
sandbox_policy_cwd: &Path,
|
||||
enforce_managed_network: bool,
|
||||
network: Option<&NetworkProxy>,
|
||||
) -> Vec<String> {
|
||||
#[derive(Debug)]
|
||||
pub struct CreateSeatbeltCommandArgsParams<'a> {
|
||||
pub command: Vec<String>,
|
||||
pub file_system_sandbox_policy: &'a FileSystemSandboxPolicy,
|
||||
pub network_sandbox_policy: NetworkSandboxPolicy,
|
||||
pub sandbox_policy_cwd: &'a Path,
|
||||
pub enforce_managed_network: bool,
|
||||
pub network: Option<&'a NetworkProxy>,
|
||||
pub extra_allow_unix_sockets: &'a [AbsolutePathBuf],
|
||||
}
|
||||
|
||||
pub fn create_seatbelt_command_args(args: CreateSeatbeltCommandArgsParams<'_>) -> Vec<String> {
|
||||
let CreateSeatbeltCommandArgsParams {
|
||||
command,
|
||||
file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
sandbox_policy_cwd,
|
||||
enforce_managed_network,
|
||||
network,
|
||||
extra_allow_unix_sockets,
|
||||
} = args;
|
||||
|
||||
let unreadable_roots =
|
||||
file_system_sandbox_policy.get_unreadable_roots_with_cwd(sandbox_policy_cwd);
|
||||
let (file_write_policy, file_write_dir_params) =
|
||||
@@ -465,7 +505,7 @@ pub fn create_seatbelt_command_args_for_policies(
|
||||
}
|
||||
};
|
||||
|
||||
let proxy = proxy_policy_inputs(network);
|
||||
let proxy = proxy_policy_inputs(network, extra_allow_unix_sockets);
|
||||
let network_policy =
|
||||
dynamic_network_policy_for_network(network_sandbox_policy, enforce_managed_network, &proxy);
|
||||
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
use super::CreateSeatbeltCommandArgsParams;
|
||||
use super::MACOS_PATH_TO_SEATBELT_EXECUTABLE;
|
||||
use super::MACOS_SEATBELT_BASE_POLICY;
|
||||
use super::ProxyPolicyInputs;
|
||||
use super::UnixDomainSocketPolicy;
|
||||
use super::create_seatbelt_command_args;
|
||||
use super::create_seatbelt_command_args_for_policies;
|
||||
use super::create_seatbelt_command_args_for_legacy_policy;
|
||||
use super::dynamic_network_policy;
|
||||
use super::macos_dir_params;
|
||||
use super::normalize_path_for_sandbox;
|
||||
use super::unix_socket_dir_params;
|
||||
use super::unix_socket_policy;
|
||||
use codex_network_proxy::ConfigReloader;
|
||||
use codex_network_proxy::ConfigState;
|
||||
use codex_network_proxy::NetworkMode;
|
||||
use codex_network_proxy::NetworkProxy;
|
||||
use codex_network_proxy::NetworkProxyConfig;
|
||||
use codex_network_proxy::NetworkProxyConstraints;
|
||||
use codex_network_proxy::NetworkProxyState;
|
||||
use codex_network_proxy::build_config_state;
|
||||
use codex_protocol::permissions::FileSystemAccessMode;
|
||||
use codex_protocol::permissions::FileSystemPath;
|
||||
use codex_protocol::permissions::FileSystemSandboxEntry;
|
||||
@@ -23,6 +32,7 @@ use std::fs;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn assert_seatbelt_denied(stderr: &[u8], path: &Path) {
|
||||
@@ -48,6 +58,23 @@ fn seatbelt_policy_arg(args: &[String]) -> &str {
|
||||
.expect("seatbelt args should include policy text")
|
||||
}
|
||||
|
||||
struct TestConfigReloader;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ConfigReloader for TestConfigReloader {
|
||||
fn source_label(&self) -> String {
|
||||
"seatbelt test config".to_string()
|
||||
}
|
||||
|
||||
async fn maybe_reload(&self) -> anyhow::Result<Option<ConfigState>> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
async fn reload_now(&self) -> anyhow::Result<ConfigState> {
|
||||
Err(anyhow::anyhow!("seatbelt test config cannot reload"))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn base_policy_allows_node_cpu_sysctls() {
|
||||
assert!(
|
||||
@@ -128,14 +155,15 @@ fn explicit_unreadable_paths_are_excluded_from_full_disk_read_and_write_access()
|
||||
},
|
||||
]);
|
||||
|
||||
let args = create_seatbelt_command_args_for_policies(
|
||||
vec!["/bin/true".to_string()],
|
||||
&file_system_policy,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
Path::new("/"),
|
||||
/*enforce_managed_network*/ false,
|
||||
/*network*/ None,
|
||||
);
|
||||
let args = create_seatbelt_command_args(CreateSeatbeltCommandArgsParams {
|
||||
command: vec!["/bin/true".to_string()],
|
||||
file_system_sandbox_policy: &file_system_policy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy::Restricted,
|
||||
sandbox_policy_cwd: Path::new("/"),
|
||||
enforce_managed_network: false,
|
||||
network: None,
|
||||
extra_allow_unix_sockets: &[],
|
||||
});
|
||||
|
||||
let policy = seatbelt_policy_arg(&args);
|
||||
let unreadable_roots = file_system_policy.get_unreadable_roots_with_cwd(Path::new("/"));
|
||||
@@ -193,14 +221,15 @@ fn explicit_unreadable_paths_are_excluded_from_readable_roots() {
|
||||
},
|
||||
]);
|
||||
|
||||
let args = create_seatbelt_command_args_for_policies(
|
||||
vec!["/bin/true".to_string()],
|
||||
&file_system_policy,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
Path::new("/"),
|
||||
/*enforce_managed_network*/ false,
|
||||
/*network*/ None,
|
||||
);
|
||||
let args = create_seatbelt_command_args(CreateSeatbeltCommandArgsParams {
|
||||
command: vec!["/bin/true".to_string()],
|
||||
file_system_sandbox_policy: &file_system_policy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy::Restricted,
|
||||
sandbox_policy_cwd: Path::new("/"),
|
||||
enforce_managed_network: false,
|
||||
network: None,
|
||||
extra_allow_unix_sockets: &[],
|
||||
});
|
||||
|
||||
let policy = seatbelt_policy_arg(&args);
|
||||
let readable_roots = file_system_policy.get_readable_roots_with_cwd(Path::new("/"));
|
||||
@@ -231,7 +260,7 @@ fn explicit_unreadable_paths_are_excluded_from_readable_roots() {
|
||||
#[test]
|
||||
fn seatbelt_args_without_extension_profile_keep_legacy_preferences_read_access() {
|
||||
let cwd = std::env::temp_dir();
|
||||
let args = create_seatbelt_command_args(
|
||||
let args = create_seatbelt_command_args_for_legacy_policy(
|
||||
vec!["echo".to_string(), "ok".to_string()],
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
cwd.as_path(),
|
||||
@@ -249,7 +278,7 @@ fn seatbelt_legacy_workspace_write_nested_readable_root_stays_writable() {
|
||||
let cwd = tmp.path().join("workspace");
|
||||
fs::create_dir_all(cwd.join("docs")).expect("create docs");
|
||||
let docs = AbsolutePathBuf::from_absolute_path(cwd.join("docs")).expect("absolute docs");
|
||||
let args = create_seatbelt_command_args(
|
||||
let args = create_seatbelt_command_args_for_legacy_policy(
|
||||
vec!["/bin/true".to_string()],
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
@@ -451,6 +480,140 @@ fn create_seatbelt_args_allowlists_unix_socket_paths() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_seatbelt_args_allowlists_explicit_unix_socket_paths_without_proxy() {
|
||||
let cwd = TempDir::new().expect("temp cwd");
|
||||
let file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
cwd.path(),
|
||||
);
|
||||
let extra_allow_unix_sockets = vec![absolute_path("/tmp/codex-browser-use")];
|
||||
let args = create_seatbelt_command_args(CreateSeatbeltCommandArgsParams {
|
||||
command: vec!["/usr/bin/true".to_string()],
|
||||
file_system_sandbox_policy: &file_system_policy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy::Restricted,
|
||||
sandbox_policy_cwd: cwd.path(),
|
||||
enforce_managed_network: false,
|
||||
network: None,
|
||||
extra_allow_unix_sockets: &extra_allow_unix_sockets,
|
||||
});
|
||||
let policy = seatbelt_policy_arg(&args);
|
||||
|
||||
assert!(
|
||||
policy.contains("(allow system-socket (socket-domain AF_UNIX))"),
|
||||
"policy should allow AF_UNIX when explicit socket paths are requested:\n{policy}"
|
||||
);
|
||||
assert!(
|
||||
policy.contains(
|
||||
"(allow network-outbound (remote unix-socket (subpath (param \"UNIX_SOCKET_PATH_0\"))))"
|
||||
),
|
||||
"policy should allow outbound AF_UNIX traffic for explicit socket paths:\n{policy}"
|
||||
);
|
||||
let expected_socket_root = normalize_path_for_sandbox(Path::new("/tmp/codex-browser-use"))
|
||||
.expect("socket root should normalize")
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
assert!(
|
||||
args.iter()
|
||||
.any(|arg| arg == &format!("-DUNIX_SOCKET_PATH_0={expected_socket_root}")),
|
||||
"seatbelt args should pass the configured socket root as a sandbox param: {args:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn create_seatbelt_args_merges_proxy_and_explicit_unix_socket_paths() -> anyhow::Result<()> {
|
||||
let cwd = TempDir::new().expect("temp cwd");
|
||||
let file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
cwd.path(),
|
||||
);
|
||||
let network_socket = "/tmp/codex-proxy-use";
|
||||
let explicit_socket = "/tmp/codex-browser-use";
|
||||
let mut network_config = NetworkProxyConfig::default();
|
||||
network_config.network.enabled = true;
|
||||
network_config.network.mode = NetworkMode::Full;
|
||||
network_config
|
||||
.network
|
||||
.set_allow_unix_sockets(vec![network_socket.to_string()]);
|
||||
let state = build_config_state(network_config, NetworkProxyConstraints::default())?;
|
||||
let network_proxy = NetworkProxy::builder()
|
||||
.state(Arc::new(NetworkProxyState::with_reloader(
|
||||
state,
|
||||
Arc::new(TestConfigReloader),
|
||||
)))
|
||||
.managed_by_codex(/*managed_by_codex*/ false)
|
||||
.build()
|
||||
.await?;
|
||||
let extra_allow_unix_sockets = vec![absolute_path(explicit_socket)];
|
||||
|
||||
let args = create_seatbelt_command_args(CreateSeatbeltCommandArgsParams {
|
||||
command: vec!["/usr/bin/true".to_string()],
|
||||
file_system_sandbox_policy: &file_system_policy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy::Restricted,
|
||||
sandbox_policy_cwd: cwd.path(),
|
||||
enforce_managed_network: false,
|
||||
network: Some(&network_proxy),
|
||||
extra_allow_unix_sockets: &extra_allow_unix_sockets,
|
||||
});
|
||||
|
||||
let expected_explicit_socket = normalize_path_for_sandbox(Path::new(explicit_socket))
|
||||
.expect("explicit socket root should normalize");
|
||||
let expected_network_socket = normalize_path_for_sandbox(Path::new(network_socket))
|
||||
.expect("network socket root should normalize");
|
||||
let unix_socket_definitions = args
|
||||
.iter()
|
||||
.filter(|arg| arg.starts_with("-DUNIX_SOCKET_PATH_"))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
unix_socket_definitions,
|
||||
vec![
|
||||
format!(
|
||||
"-DUNIX_SOCKET_PATH_0={}",
|
||||
expected_explicit_socket.display()
|
||||
),
|
||||
format!("-DUNIX_SOCKET_PATH_1={}", expected_network_socket.display()),
|
||||
],
|
||||
"seatbelt args should include both explicit and network proxy socket roots: {args:?}"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_seatbelt_args_preserves_full_network_with_explicit_unix_socket_paths() {
|
||||
let cwd = TempDir::new().expect("temp cwd");
|
||||
let file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
cwd.path(),
|
||||
);
|
||||
let extra_allow_unix_sockets = vec![absolute_path("/tmp/codex-browser-use")];
|
||||
let args = create_seatbelt_command_args(CreateSeatbeltCommandArgsParams {
|
||||
command: vec!["/usr/bin/true".to_string()],
|
||||
file_system_sandbox_policy: &file_system_policy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy::Enabled,
|
||||
sandbox_policy_cwd: cwd.path(),
|
||||
enforce_managed_network: false,
|
||||
network: None,
|
||||
extra_allow_unix_sockets: &extra_allow_unix_sockets,
|
||||
});
|
||||
let policy = seatbelt_policy_arg(&args);
|
||||
|
||||
assert!(
|
||||
policy.contains("(allow network-outbound)\n"),
|
||||
"policy should preserve full outbound network access:\n{policy}"
|
||||
);
|
||||
assert!(
|
||||
policy.contains("(allow network-inbound)\n"),
|
||||
"policy should preserve full inbound network access:\n{policy}"
|
||||
);
|
||||
assert!(
|
||||
policy.contains(
|
||||
"(allow network-outbound (remote unix-socket (subpath (param \"UNIX_SOCKET_PATH_0\"))))"
|
||||
),
|
||||
"policy should still allow outbound AF_UNIX traffic for explicit socket paths:\n{policy}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unix_socket_policy_non_empty_output_is_newline_terminated() {
|
||||
let allowlist_policy = unix_socket_policy(&ProxyPolicyInputs {
|
||||
@@ -615,7 +778,7 @@ fn create_seatbelt_args_with_read_only_git_and_codex_subpaths() {
|
||||
.iter()
|
||||
.map(std::string::ToString::to_string)
|
||||
.collect();
|
||||
let args = create_seatbelt_command_args(
|
||||
let args = create_seatbelt_command_args_for_legacy_policy(
|
||||
shell_command.clone(),
|
||||
&policy,
|
||||
&cwd,
|
||||
@@ -729,7 +892,7 @@ fn create_seatbelt_args_with_read_only_git_and_codex_subpaths() {
|
||||
.iter()
|
||||
.map(std::string::ToString::to_string)
|
||||
.collect();
|
||||
let write_hooks_file_args = create_seatbelt_command_args(
|
||||
let write_hooks_file_args = create_seatbelt_command_args_for_legacy_policy(
|
||||
shell_command_git,
|
||||
&policy,
|
||||
&cwd,
|
||||
@@ -765,7 +928,7 @@ fn create_seatbelt_args_with_read_only_git_and_codex_subpaths() {
|
||||
.iter()
|
||||
.map(std::string::ToString::to_string)
|
||||
.collect();
|
||||
let write_allowed_file_args = create_seatbelt_command_args(
|
||||
let write_allowed_file_args = create_seatbelt_command_args_for_legacy_policy(
|
||||
shell_command_allowed,
|
||||
&policy,
|
||||
&cwd,
|
||||
@@ -830,7 +993,7 @@ fn create_seatbelt_args_block_first_time_dot_codex_creation_with_exact_and_desce
|
||||
.iter()
|
||||
.map(std::string::ToString::to_string)
|
||||
.collect();
|
||||
let args = create_seatbelt_command_args(
|
||||
let args = create_seatbelt_command_args_for_legacy_policy(
|
||||
shell_command,
|
||||
&policy,
|
||||
repo_root.as_path(),
|
||||
@@ -885,7 +1048,7 @@ fn create_seatbelt_args_with_read_only_git_pointer_file() {
|
||||
.iter()
|
||||
.map(std::string::ToString::to_string)
|
||||
.collect();
|
||||
let args = create_seatbelt_command_args(
|
||||
let args = create_seatbelt_command_args_for_legacy_policy(
|
||||
shell_command,
|
||||
&policy,
|
||||
&cwd,
|
||||
@@ -921,7 +1084,7 @@ fn create_seatbelt_args_with_read_only_git_pointer_file() {
|
||||
.iter()
|
||||
.map(std::string::ToString::to_string)
|
||||
.collect();
|
||||
let gitdir_args = create_seatbelt_command_args(
|
||||
let gitdir_args = create_seatbelt_command_args_for_legacy_policy(
|
||||
shell_command_gitdir,
|
||||
&policy,
|
||||
&cwd,
|
||||
@@ -984,7 +1147,7 @@ fn create_seatbelt_args_for_cwd_as_git_repo() {
|
||||
.iter()
|
||||
.map(std::string::ToString::to_string)
|
||||
.collect();
|
||||
let args = create_seatbelt_command_args(
|
||||
let args = create_seatbelt_command_args_for_legacy_policy(
|
||||
shell_command.clone(),
|
||||
&policy,
|
||||
vulnerable_root.as_path(),
|
||||
|
||||
Reference in new issue
Block a user