mirror of
https://github.com/openai/codex.git
synced 2026-10-30 19:18:49 +00:00
Allow trusted symlinks beneath CODEX_HOME on macOS (#42716)
## What changed - Add the macOS-only `allow_symlinked_codex_home` user setting. When enabled in the execution host's `$CODEX_HOME/config.toml`, writable roots at or beneath that home may traverse symlinks. - Keep the exception disabled by default and prevent project config, command-line overrides, and ignored user config from enabling it. Other writable roots remain subject to symlink checks. - Propagate the resolved setting through local, interactive, and exec-server sandbox paths, including `CODEX_HOME` aliases. - Explain the opt-out in symlink rejection errors, including that it trusts targets outside `CODEX_HOME` and targets that change between commands. ## Testing - Add macOS coverage for shell commands, patches, filesystem helpers, process execution, and interactive startup with enabled, disabled, aliased, and out-of-scope homes. GitOrigin-RevId: 99fcdf611200c9e1b7713cf06f7fdea5bfa7f089
This commit is contained in:
@@ -37,9 +37,7 @@ use codex_sandboxing::policy_transforms::effective_network_sandbox_policy;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
pub(crate) struct ToolOrchestrator {
|
||||
sandbox: SandboxManager,
|
||||
}
|
||||
pub(crate) struct ToolOrchestrator;
|
||||
|
||||
pub(crate) struct OrchestratorRunResult<Out> {
|
||||
pub output: Out,
|
||||
@@ -48,9 +46,7 @@ pub(crate) struct OrchestratorRunResult<Out> {
|
||||
|
||||
impl ToolOrchestrator {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
sandbox: SandboxManager::new(),
|
||||
}
|
||||
Self
|
||||
}
|
||||
|
||||
async fn run_attempt<Rq, Out, T>(
|
||||
@@ -145,6 +141,14 @@ impl ToolOrchestrator {
|
||||
let mut already_approved = false;
|
||||
|
||||
let environment = tool.turn_environment(req);
|
||||
let sandbox_manager = SandboxManager::new();
|
||||
#[cfg(target_os = "macos")]
|
||||
let sandbox_manager = sandbox_manager.with_allowed_symlinked_codex_home(
|
||||
environment
|
||||
.environment
|
||||
.local_runtime_paths()
|
||||
.and_then(|paths| paths.allowed_symlinked_codex_home.clone()),
|
||||
);
|
||||
let sandbox_config = environment.config();
|
||||
let owner_network_policy = sandbox_config.network_policy.is_some();
|
||||
if owner_network_policy
|
||||
@@ -264,14 +268,14 @@ impl ToolOrchestrator {
|
||||
let sandbox_preference = tool.sandbox_preference();
|
||||
let sandbox_requested = match sandbox_override {
|
||||
SandboxOverride::BypassSandboxFirstAttempt => false,
|
||||
SandboxOverride::NoOverride => self.sandbox.should_sandbox(
|
||||
SandboxOverride::NoOverride => sandbox_manager.should_sandbox(
|
||||
&permissions,
|
||||
sandbox_preference,
|
||||
managed_network_active,
|
||||
),
|
||||
};
|
||||
let initial_sandbox = if sandbox_requested && !executor_managed_process_sandbox {
|
||||
self.sandbox.select_initial(
|
||||
sandbox_manager.select_initial(
|
||||
&permissions,
|
||||
sandbox_preference,
|
||||
sandbox_config.windows_sandbox_level,
|
||||
@@ -291,7 +295,7 @@ impl ToolOrchestrator {
|
||||
permissions: &permissions,
|
||||
exec_server_permissions: permission_profile,
|
||||
enforce_managed_network: managed_network_active,
|
||||
manager: &self.sandbox,
|
||||
manager: &sandbox_manager,
|
||||
sandbox_cwd: &sandbox_policy_cwd,
|
||||
workspace_roots,
|
||||
codex_linux_sandbox_exe: turn_ctx.config.codex_linux_sandbox_exe.as_ref(),
|
||||
@@ -438,14 +442,14 @@ impl ToolOrchestrator {
|
||||
}
|
||||
|
||||
let retry_sandbox_requested = !unsandboxed_allowed
|
||||
&& self.sandbox.should_sandbox(
|
||||
&& sandbox_manager.should_sandbox(
|
||||
&permissions,
|
||||
sandbox_preference,
|
||||
managed_network_active,
|
||||
);
|
||||
let retry_sandbox = if retry_sandbox_requested && !executor_managed_process_sandbox
|
||||
{
|
||||
self.sandbox.select_initial(
|
||||
sandbox_manager.select_initial(
|
||||
&permissions,
|
||||
sandbox_preference,
|
||||
sandbox_config.windows_sandbox_level,
|
||||
@@ -465,7 +469,7 @@ impl ToolOrchestrator {
|
||||
permissions: &permissions,
|
||||
exec_server_permissions: permission_profile,
|
||||
enforce_managed_network: managed_network_active,
|
||||
manager: &self.sandbox,
|
||||
manager: &sandbox_manager,
|
||||
sandbox_cwd: &sandbox_policy_cwd,
|
||||
workspace_roots,
|
||||
codex_linux_sandbox_exe: retry_codex_linux_sandbox_exe,
|
||||
|
||||
@@ -84,7 +84,7 @@ fn approval_sandbox_permissions(
|
||||
|
||||
pub(crate) async fn prepare_unified_exec_zsh_fork(
|
||||
req: &crate::tools::runtimes::unified_exec::UnifiedExecRequest,
|
||||
_attempt: &SandboxAttempt<'_>,
|
||||
attempt: &SandboxAttempt<'_>,
|
||||
ctx: &ToolCtx,
|
||||
exec_request: ExecRequest,
|
||||
shell_zsh_path: &std::path::Path,
|
||||
@@ -128,6 +128,7 @@ pub(crate) async fn prepare_unified_exec_zsh_fork(
|
||||
.to_abs_path()
|
||||
.map_err(|err| ToolError::Rejected(err.to_string()))?;
|
||||
let command_executor = CoreShellCommandExecutor {
|
||||
sandbox_manager: attempt.manager.clone(),
|
||||
command: exec_request.command.clone(),
|
||||
cwd,
|
||||
permission_profile: exec_request.permission_profile.clone(),
|
||||
@@ -565,6 +566,7 @@ fn commands_for_intercepted_exec_policy(
|
||||
// TODO(anp): Capture these Windows and Landlock settings from
|
||||
// TurnEnvironment::sandbox_context when preparing this executor, preserving its snapshot.
|
||||
struct CoreShellCommandExecutor {
|
||||
sandbox_manager: SandboxManager,
|
||||
command: Vec<String>,
|
||||
cwd: AbsolutePathBuf,
|
||||
permission_profile: PermissionProfile,
|
||||
@@ -757,7 +759,7 @@ impl CoreShellCommandExecutor {
|
||||
let (program, args) = command
|
||||
.split_first()
|
||||
.ok_or_else(|| anyhow::anyhow!("prepared command must not be empty"))?;
|
||||
let sandbox_manager = SandboxManager::new();
|
||||
let sandbox_manager = &self.sandbox_manager;
|
||||
let sandbox = sandbox_manager.select_initial(
|
||||
permission_profile,
|
||||
SandboxablePreference::Auto,
|
||||
|
||||
@@ -358,6 +358,7 @@ async fn unsandboxed_intercepted_exec_strips_managed_network_env() -> anyhow::Re
|
||||
let workdir = test_sandbox_cwd();
|
||||
let network = test_credential_broker_network_proxy().await?;
|
||||
let executor = CoreShellCommandExecutor {
|
||||
sandbox_manager: codex_sandboxing::SandboxManager::new(),
|
||||
command: Vec::new(),
|
||||
cwd: workdir.clone(),
|
||||
permission_profile: PermissionProfile::workspace_write(),
|
||||
|
||||
Reference in New Issue
Block a user