mirror of
https://github.com/openai/codex.git
synced 2026-10-30 19:18:49 +00:00
Merge 3d8f475bce into sapling-pr-archive-bolinfest
This commit is contained in:
@@ -1506,9 +1506,19 @@ impl CodexMessageProcessor {
|
||||
};
|
||||
|
||||
let requested_policy = params.sandbox_policy.map(|policy| policy.to_core());
|
||||
let effective_policy = match requested_policy {
|
||||
let (
|
||||
effective_policy,
|
||||
effective_file_system_sandbox_policy,
|
||||
effective_network_sandbox_policy,
|
||||
) = match requested_policy {
|
||||
Some(policy) => match self.config.permissions.sandbox_policy.can_set(&policy) {
|
||||
Ok(()) => policy,
|
||||
Ok(()) => {
|
||||
let file_system_sandbox_policy =
|
||||
codex_protocol::protocol::FileSystemSandboxPolicy::from(&policy);
|
||||
let network_sandbox_policy =
|
||||
codex_protocol::protocol::NetworkSandboxPolicy::from(&policy);
|
||||
(policy, file_system_sandbox_policy, network_sandbox_policy)
|
||||
}
|
||||
Err(err) => {
|
||||
let error = JSONRPCErrorError {
|
||||
code: INVALID_REQUEST_ERROR_CODE,
|
||||
@@ -1519,7 +1529,11 @@ impl CodexMessageProcessor {
|
||||
return;
|
||||
}
|
||||
},
|
||||
None => self.config.permissions.sandbox_policy.get().clone(),
|
||||
None => (
|
||||
self.config.permissions.sandbox_policy.get().clone(),
|
||||
self.config.permissions.file_system_sandbox_policy.clone(),
|
||||
self.config.permissions.network_sandbox_policy,
|
||||
),
|
||||
};
|
||||
|
||||
let codex_linux_sandbox_exe = self.arg0_paths.codex_linux_sandbox_exe.clone();
|
||||
@@ -1534,6 +1548,8 @@ impl CodexMessageProcessor {
|
||||
match codex_core::exec::process_exec_tool_call(
|
||||
exec_params,
|
||||
&effective_policy,
|
||||
&effective_file_system_sandbox_policy,
|
||||
effective_network_sandbox_policy,
|
||||
sandbox_cwd.as_path(),
|
||||
&codex_linux_sandbox_exe,
|
||||
use_linux_sandbox_bwrap,
|
||||
|
||||
@@ -222,10 +222,12 @@ use crate::protocol::ErrorEvent;
|
||||
use crate::protocol::Event;
|
||||
use crate::protocol::EventMsg;
|
||||
use crate::protocol::ExecApprovalRequestEvent;
|
||||
use crate::protocol::FileSystemSandboxPolicy;
|
||||
use crate::protocol::McpServerRefreshConfig;
|
||||
use crate::protocol::ModelRerouteEvent;
|
||||
use crate::protocol::ModelRerouteReason;
|
||||
use crate::protocol::NetworkApprovalContext;
|
||||
use crate::protocol::NetworkSandboxPolicy;
|
||||
use crate::protocol::Op;
|
||||
use crate::protocol::PlanDeltaEvent;
|
||||
use crate::protocol::RateLimitSnapshot;
|
||||
@@ -482,6 +484,8 @@ impl Codex {
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
sandbox_policy: config.permissions.sandbox_policy.clone(),
|
||||
file_system_sandbox_policy: config.permissions.file_system_sandbox_policy.clone(),
|
||||
network_sandbox_policy: config.permissions.network_sandbox_policy,
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -676,6 +680,8 @@ pub(crate) struct TurnContext {
|
||||
pub(crate) personality: Option<Personality>,
|
||||
pub(crate) approval_policy: Constrained<AskForApproval>,
|
||||
pub(crate) sandbox_policy: Constrained<SandboxPolicy>,
|
||||
pub(crate) file_system_sandbox_policy: FileSystemSandboxPolicy,
|
||||
pub(crate) network_sandbox_policy: NetworkSandboxPolicy,
|
||||
pub(crate) network: Option<NetworkProxy>,
|
||||
pub(crate) windows_sandbox_level: WindowsSandboxLevel,
|
||||
pub(crate) shell_environment_policy: ShellEnvironmentPolicy,
|
||||
@@ -764,6 +770,8 @@ impl TurnContext {
|
||||
personality: self.personality,
|
||||
approval_policy: self.approval_policy.clone(),
|
||||
sandbox_policy: self.sandbox_policy.clone(),
|
||||
file_system_sandbox_policy: self.file_system_sandbox_policy.clone(),
|
||||
network_sandbox_policy: self.network_sandbox_policy,
|
||||
network: self.network.clone(),
|
||||
windows_sandbox_level: self.windows_sandbox_level,
|
||||
shell_environment_policy: self.shell_environment_policy.clone(),
|
||||
@@ -867,6 +875,8 @@ pub(crate) struct SessionConfiguration {
|
||||
approval_policy: Constrained<AskForApproval>,
|
||||
/// How to sandbox commands executed in the system
|
||||
sandbox_policy: Constrained<SandboxPolicy>,
|
||||
file_system_sandbox_policy: FileSystemSandboxPolicy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
windows_sandbox_level: WindowsSandboxLevel,
|
||||
|
||||
/// Working directory that should be treated as the *root* of the
|
||||
@@ -933,6 +943,10 @@ impl SessionConfiguration {
|
||||
}
|
||||
if let Some(sandbox_policy) = updates.sandbox_policy.clone() {
|
||||
next_configuration.sandbox_policy.set(sandbox_policy)?;
|
||||
next_configuration.file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from(next_configuration.sandbox_policy.get());
|
||||
next_configuration.network_sandbox_policy =
|
||||
NetworkSandboxPolicy::from(next_configuration.sandbox_policy.get());
|
||||
}
|
||||
if let Some(windows_sandbox_level) = updates.windows_sandbox_level {
|
||||
next_configuration.windows_sandbox_level = windows_sandbox_level;
|
||||
@@ -1145,6 +1159,8 @@ impl Session {
|
||||
personality: session_configuration.personality,
|
||||
approval_policy: session_configuration.approval_policy.clone(),
|
||||
sandbox_policy: session_configuration.sandbox_policy.clone(),
|
||||
file_system_sandbox_policy: session_configuration.file_system_sandbox_policy.clone(),
|
||||
network_sandbox_policy: session_configuration.network_sandbox_policy,
|
||||
network,
|
||||
windows_sandbox_level: session_configuration.windows_sandbox_level,
|
||||
shell_environment_policy: per_turn_config.permissions.shell_environment_policy.clone(),
|
||||
@@ -4805,6 +4821,8 @@ async fn spawn_review_thread(
|
||||
personality: parent_turn_context.personality,
|
||||
approval_policy: parent_turn_context.approval_policy.clone(),
|
||||
sandbox_policy: parent_turn_context.sandbox_policy.clone(),
|
||||
file_system_sandbox_policy: parent_turn_context.file_system_sandbox_policy.clone(),
|
||||
network_sandbox_policy: parent_turn_context.network_sandbox_policy,
|
||||
network: parent_turn_context.network.clone(),
|
||||
windows_sandbox_level: parent_turn_context.windows_sandbox_level,
|
||||
shell_environment_policy: parent_turn_context.shell_environment_policy.clone(),
|
||||
@@ -7832,6 +7850,8 @@ mod tests {
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
sandbox_policy: config.permissions.sandbox_policy.clone(),
|
||||
file_system_sandbox_policy: config.permissions.file_system_sandbox_policy.clone(),
|
||||
network_sandbox_policy: config.permissions.network_sandbox_policy,
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -7927,6 +7947,8 @@ mod tests {
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
sandbox_policy: config.permissions.sandbox_policy.clone(),
|
||||
file_system_sandbox_policy: config.permissions.file_system_sandbox_policy.clone(),
|
||||
network_sandbox_policy: config.permissions.network_sandbox_policy,
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -8247,6 +8269,8 @@ mod tests {
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
sandbox_policy: config.permissions.sandbox_policy.clone(),
|
||||
file_system_sandbox_policy: config.permissions.file_system_sandbox_policy.clone(),
|
||||
network_sandbox_policy: config.permissions.network_sandbox_policy,
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -8306,6 +8330,8 @@ mod tests {
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
sandbox_policy: config.permissions.sandbox_policy.clone(),
|
||||
file_system_sandbox_policy: config.permissions.file_system_sandbox_policy.clone(),
|
||||
network_sandbox_policy: config.permissions.network_sandbox_policy,
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -8398,6 +8424,8 @@ mod tests {
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
sandbox_policy: config.permissions.sandbox_policy.clone(),
|
||||
file_system_sandbox_policy: config.permissions.file_system_sandbox_policy.clone(),
|
||||
network_sandbox_policy: config.permissions.network_sandbox_policy,
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -8647,6 +8675,8 @@ mod tests {
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
sandbox_policy: config.permissions.sandbox_policy.clone(),
|
||||
file_system_sandbox_policy: config.permissions.file_system_sandbox_policy.clone(),
|
||||
network_sandbox_policy: config.permissions.network_sandbox_policy,
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
|
||||
+30
-10
@@ -24,6 +24,9 @@ use crate::protocol::Event;
|
||||
use crate::protocol::EventMsg;
|
||||
use crate::protocol::ExecCommandOutputDeltaEvent;
|
||||
use crate::protocol::ExecOutputStream;
|
||||
use crate::protocol::FileSystemSandboxKind;
|
||||
use crate::protocol::FileSystemSandboxPolicy;
|
||||
use crate::protocol::NetworkSandboxPolicy;
|
||||
use crate::protocol::SandboxPolicy;
|
||||
use crate::sandboxing::CommandSpec;
|
||||
use crate::sandboxing::ExecRequest;
|
||||
@@ -149,9 +152,12 @@ pub struct StdoutStream {
|
||||
pub tx_event: Sender<Event>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn process_exec_tool_call(
|
||||
params: ExecParams,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
sandbox_cwd: &Path,
|
||||
codex_linux_sandbox_exe: &Option<PathBuf>,
|
||||
use_linux_sandbox_bwrap: bool,
|
||||
@@ -159,8 +165,8 @@ pub async fn process_exec_tool_call(
|
||||
) -> Result<ExecToolCallOutput> {
|
||||
let windows_sandbox_level = params.windows_sandbox_level;
|
||||
let enforce_managed_network = params.network.is_some();
|
||||
let sandbox_type = match &sandbox_policy {
|
||||
SandboxPolicy::DangerFullAccess | SandboxPolicy::ExternalSandbox { .. } => {
|
||||
let sandbox_type = match file_system_sandbox_policy.kind {
|
||||
FileSystemSandboxKind::Unrestricted | FileSystemSandboxKind::ExternalSandbox => {
|
||||
if enforce_managed_network {
|
||||
get_platform_sandbox(
|
||||
windows_sandbox_level
|
||||
@@ -215,6 +221,8 @@ pub async fn process_exec_tool_call(
|
||||
.transform(crate::sandboxing::SandboxTransformRequest {
|
||||
spec,
|
||||
policy: sandbox_policy,
|
||||
file_system_policy: file_system_sandbox_policy,
|
||||
network_policy: network_sandbox_policy,
|
||||
sandbox: sandbox_type,
|
||||
enforce_managed_network,
|
||||
network: network.as_ref(),
|
||||
@@ -233,7 +241,6 @@ pub async fn process_exec_tool_call(
|
||||
|
||||
pub(crate) async fn execute_exec_env(
|
||||
env: ExecRequest,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
stdout_stream: Option<StdoutStream>,
|
||||
) -> Result<ExecToolCallOutput> {
|
||||
let ExecRequest {
|
||||
@@ -245,7 +252,9 @@ pub(crate) async fn execute_exec_env(
|
||||
sandbox,
|
||||
windows_sandbox_level,
|
||||
sandbox_permissions,
|
||||
sandbox_policy: _sandbox_policy_from_env,
|
||||
sandbox_policy,
|
||||
file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
justification,
|
||||
arg0,
|
||||
} = env;
|
||||
@@ -263,7 +272,15 @@ pub(crate) async fn execute_exec_env(
|
||||
};
|
||||
|
||||
let start = Instant::now();
|
||||
let raw_output_result = exec(params, sandbox, sandbox_policy, stdout_stream).await;
|
||||
let raw_output_result = exec(
|
||||
params,
|
||||
sandbox,
|
||||
&sandbox_policy,
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
stdout_stream,
|
||||
)
|
||||
.await;
|
||||
let duration = start.elapsed();
|
||||
finalize_exec_result(raw_output_result, sandbox, duration)
|
||||
}
|
||||
@@ -692,14 +709,13 @@ async fn exec(
|
||||
params: ExecParams,
|
||||
sandbox: SandboxType,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
stdout_stream: Option<StdoutStream>,
|
||||
) -> Result<RawExecToolCallOutput> {
|
||||
#[cfg(target_os = "windows")]
|
||||
if sandbox == SandboxType::WindowsRestrictedToken
|
||||
&& !matches!(
|
||||
sandbox_policy,
|
||||
SandboxPolicy::DangerFullAccess | SandboxPolicy::ExternalSandbox { .. }
|
||||
)
|
||||
&& file_system_sandbox_policy.kind == FileSystemSandboxKind::Restricted
|
||||
{
|
||||
return exec_windows_sandbox(params, sandbox_policy).await;
|
||||
}
|
||||
@@ -729,7 +745,7 @@ async fn exec(
|
||||
args: args.into(),
|
||||
arg0: arg0_ref,
|
||||
cwd,
|
||||
sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
// The environment already has attempt-scoped proxy settings from
|
||||
// apply_to_env_for_attempt above. Passing network here would reapply
|
||||
// non-attempt proxy vars and drop attempt correlation metadata.
|
||||
@@ -1135,6 +1151,8 @@ mod tests {
|
||||
params,
|
||||
SandboxType::None,
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
&FileSystemSandboxPolicy::from(&SandboxPolicy::new_read_only_policy()),
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
@@ -1190,6 +1208,8 @@ mod tests {
|
||||
let result = process_exec_tool_call(
|
||||
params,
|
||||
&SandboxPolicy::DangerFullAccess,
|
||||
&FileSystemSandboxPolicy::from(&SandboxPolicy::DangerFullAccess),
|
||||
NetworkSandboxPolicy::Enabled,
|
||||
cwd.as_path(),
|
||||
&None,
|
||||
false,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::protocol::NetworkSandboxPolicy;
|
||||
use crate::protocol::SandboxPolicy;
|
||||
use crate::spawn::SpawnChildRequest;
|
||||
use crate::spawn::StdioPolicy;
|
||||
@@ -44,7 +45,7 @@ where
|
||||
args,
|
||||
arg0,
|
||||
cwd: command_cwd,
|
||||
sandbox_policy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy::from(sandbox_policy),
|
||||
network,
|
||||
stdio_policy,
|
||||
env,
|
||||
|
||||
@@ -13,6 +13,9 @@ use crate::exec::StdoutStream;
|
||||
use crate::exec::execute_exec_env;
|
||||
use crate::landlock::allow_network_for_proxy;
|
||||
use crate::landlock::create_linux_sandbox_command_args;
|
||||
use crate::protocol::FileSystemSandboxKind;
|
||||
use crate::protocol::FileSystemSandboxPolicy;
|
||||
use crate::protocol::NetworkSandboxPolicy;
|
||||
use crate::protocol::SandboxPolicy;
|
||||
#[cfg(target_os = "macos")]
|
||||
use crate::seatbelt::MACOS_PATH_TO_SEATBELT_EXECUTABLE;
|
||||
@@ -60,6 +63,8 @@ pub struct ExecRequest {
|
||||
pub windows_sandbox_level: WindowsSandboxLevel,
|
||||
pub sandbox_permissions: SandboxPermissions,
|
||||
pub sandbox_policy: SandboxPolicy,
|
||||
pub file_system_sandbox_policy: FileSystemSandboxPolicy,
|
||||
pub network_sandbox_policy: NetworkSandboxPolicy,
|
||||
pub justification: Option<String>,
|
||||
pub arg0: Option<String>,
|
||||
}
|
||||
@@ -70,6 +75,8 @@ pub struct ExecRequest {
|
||||
pub(crate) struct SandboxTransformRequest<'a> {
|
||||
pub spec: CommandSpec,
|
||||
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>>
|
||||
@@ -270,7 +277,7 @@ impl SandboxManager {
|
||||
|
||||
pub(crate) fn select_initial(
|
||||
&self,
|
||||
policy: &SandboxPolicy,
|
||||
file_system_policy: &FileSystemSandboxPolicy,
|
||||
pref: SandboxablePreference,
|
||||
windows_sandbox_level: WindowsSandboxLevel,
|
||||
has_managed_network_requirements: bool,
|
||||
@@ -285,8 +292,8 @@ impl SandboxManager {
|
||||
)
|
||||
.unwrap_or(SandboxType::None)
|
||||
}
|
||||
SandboxablePreference::Auto => match policy {
|
||||
SandboxPolicy::DangerFullAccess | SandboxPolicy::ExternalSandbox { .. } => {
|
||||
SandboxablePreference::Auto => match file_system_policy.kind {
|
||||
FileSystemSandboxKind::Unrestricted | FileSystemSandboxKind::ExternalSandbox => {
|
||||
if has_managed_network_requirements {
|
||||
crate::safety::get_platform_sandbox(
|
||||
windows_sandbox_level != WindowsSandboxLevel::Disabled,
|
||||
@@ -311,6 +318,8 @@ impl SandboxManager {
|
||||
let SandboxTransformRequest {
|
||||
mut spec,
|
||||
policy,
|
||||
file_system_policy,
|
||||
network_policy,
|
||||
sandbox,
|
||||
enforce_managed_network,
|
||||
network,
|
||||
@@ -321,14 +330,45 @@ impl SandboxManager {
|
||||
use_linux_sandbox_bwrap,
|
||||
windows_sandbox_level,
|
||||
} = request;
|
||||
let effective_policy =
|
||||
if let Some(additional_permissions) = spec.additional_permissions.take() {
|
||||
sandbox_policy_with_additional_permissions(policy, &additional_permissions)?
|
||||
let effective_policy = if let Some(additional_permissions) =
|
||||
spec.additional_permissions.take()
|
||||
{
|
||||
let (extra_reads, extra_writes) = additional_permission_roots(&additional_permissions);
|
||||
let effective_policy =
|
||||
sandbox_policy_with_additional_permissions(policy, &additional_permissions)?;
|
||||
let file_system_sandbox_policy = if extra_reads.is_empty() && extra_writes.is_empty() {
|
||||
file_system_policy.clone()
|
||||
} else {
|
||||
policy.clone()
|
||||
match file_system_policy.kind {
|
||||
FileSystemSandboxKind::Restricted => {
|
||||
FileSystemSandboxPolicy::from(&effective_policy)
|
||||
}
|
||||
FileSystemSandboxKind::Unrestricted
|
||||
| FileSystemSandboxKind::ExternalSandbox => file_system_policy.clone(),
|
||||
}
|
||||
};
|
||||
let network_sandbox_policy = if additional_permissions
|
||||
.network
|
||||
.as_ref()
|
||||
.and_then(|network| network.enabled)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
NetworkSandboxPolicy::Enabled
|
||||
} else {
|
||||
network_policy
|
||||
};
|
||||
(
|
||||
effective_policy,
|
||||
file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
)
|
||||
} else {
|
||||
(policy.clone(), file_system_policy.clone(), network_policy)
|
||||
};
|
||||
let (effective_policy, effective_file_system_policy, effective_network_policy) =
|
||||
effective_policy;
|
||||
let mut env = spec.env;
|
||||
if !effective_policy.has_full_network_access() {
|
||||
if !effective_network_policy.is_enabled() {
|
||||
env.insert(
|
||||
CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR.to_string(),
|
||||
"1".to_string(),
|
||||
@@ -402,6 +442,8 @@ impl SandboxManager {
|
||||
windows_sandbox_level,
|
||||
sandbox_permissions: spec.sandbox_permissions,
|
||||
sandbox_policy: effective_policy,
|
||||
file_system_sandbox_policy: effective_file_system_policy,
|
||||
network_sandbox_policy: effective_network_policy,
|
||||
justification: spec.justification,
|
||||
arg0: arg0_override,
|
||||
})
|
||||
@@ -416,8 +458,7 @@ pub async fn execute_env(
|
||||
env: ExecRequest,
|
||||
stdout_stream: Option<StdoutStream>,
|
||||
) -> crate::error::Result<ExecToolCallOutput> {
|
||||
let effective_policy = env.sandbox_policy.clone();
|
||||
execute_exec_env(env, &effective_policy, stdout_stream).await
|
||||
execute_exec_env(env, stdout_stream).await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -426,6 +467,13 @@ mod tests {
|
||||
use super::normalize_additional_permissions;
|
||||
use super::sandbox_policy_with_additional_permissions;
|
||||
use crate::exec::SandboxType;
|
||||
use crate::protocol::FileSystemAccessMode;
|
||||
use crate::protocol::FileSystemPath;
|
||||
use crate::protocol::FileSystemSandboxEntry;
|
||||
use crate::protocol::FileSystemSandboxPolicy;
|
||||
use crate::protocol::FileSystemSpecialPath;
|
||||
use crate::protocol::FileSystemSpecialPathKind;
|
||||
use crate::protocol::NetworkSandboxPolicy;
|
||||
use crate::protocol::ReadOnlyAccess;
|
||||
use crate::protocol::SandboxPolicy;
|
||||
use crate::tools::sandboxing::SandboxablePreference;
|
||||
@@ -435,13 +483,14 @@ mod tests {
|
||||
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(
|
||||
&SandboxPolicy::DangerFullAccess,
|
||||
&FileSystemSandboxPolicy::unrestricted(),
|
||||
SandboxablePreference::Auto,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
false,
|
||||
@@ -454,7 +503,7 @@ mod tests {
|
||||
let manager = SandboxManager::new();
|
||||
let expected = crate::safety::get_platform_sandbox(false).unwrap_or(SandboxType::None);
|
||||
let sandbox = manager.select_initial(
|
||||
&SandboxPolicy::DangerFullAccess,
|
||||
&FileSystemSandboxPolicy::unrestricted(),
|
||||
SandboxablePreference::Auto,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
true,
|
||||
@@ -462,6 +511,70 @@ mod tests {
|
||||
assert_eq!(sandbox, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn restricted_file_system_uses_platform_sandbox_without_managed_network() {
|
||||
let manager = SandboxManager::new();
|
||||
let expected = crate::safety::get_platform_sandbox(false).unwrap_or(SandboxType::None);
|
||||
let sandbox = manager.select_initial(
|
||||
&FileSystemSandboxPolicy::restricted(vec![FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath {
|
||||
kind: FileSystemSpecialPathKind::Root,
|
||||
subpath: None,
|
||||
},
|
||||
},
|
||||
access: FileSystemAccessMode::Read,
|
||||
}]),
|
||||
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(super::SandboxTransformRequest {
|
||||
spec: super::CommandSpec {
|
||||
program: "true".to_string(),
|
||||
args: Vec::new(),
|
||||
cwd: cwd.clone(),
|
||||
env: HashMap::new(),
|
||||
expiration: crate::exec::ExecExpiration::DefaultTimeout,
|
||||
sandbox_permissions: super::SandboxPermissions::UseDefault,
|
||||
additional_permissions: None,
|
||||
justification: None,
|
||||
},
|
||||
policy: &SandboxPolicy::ExternalSandbox {
|
||||
network_access: crate::protocol::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_linux_sandbox_bwrap: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
})
|
||||
.expect("transform");
|
||||
|
||||
assert_eq!(
|
||||
exec_request.file_system_sandbox_policy,
|
||||
FileSystemSandboxPolicy::unrestricted()
|
||||
);
|
||||
assert_eq!(
|
||||
exec_request.network_sandbox_policy,
|
||||
NetworkSandboxPolicy::Restricted
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_additional_permissions_preserves_network() {
|
||||
let temp_dir = TempDir::new().expect("create temp dir");
|
||||
|
||||
@@ -15,6 +15,7 @@ use tokio::process::Child;
|
||||
use tracing::warn;
|
||||
use url::Url;
|
||||
|
||||
use crate::protocol::NetworkSandboxPolicy;
|
||||
use crate::protocol::SandboxPolicy;
|
||||
use crate::seatbelt_permissions::MacOsSeatbeltProfileExtensions;
|
||||
use crate::seatbelt_permissions::build_seatbelt_extensions;
|
||||
@@ -51,7 +52,7 @@ pub async fn spawn_command_under_seatbelt(
|
||||
args,
|
||||
arg0,
|
||||
cwd: command_cwd,
|
||||
sandbox_policy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy::from(sandbox_policy),
|
||||
network,
|
||||
stdio_policy,
|
||||
env,
|
||||
|
||||
@@ -6,13 +6,13 @@ use tokio::process::Child;
|
||||
use tokio::process::Command;
|
||||
use tracing::trace;
|
||||
|
||||
use crate::protocol::SandboxPolicy;
|
||||
use crate::protocol::NetworkSandboxPolicy;
|
||||
|
||||
/// Experimental environment variable that will be set to some non-empty value
|
||||
/// if both of the following are true:
|
||||
///
|
||||
/// 1. The process was spawned by Codex as part of a shell tool call.
|
||||
/// 2. SandboxPolicy.has_full_network_access() was false for the tool call.
|
||||
/// 2. NetworkSandboxPolicy is restricted for the tool call.
|
||||
///
|
||||
/// We may try to have just one environment variable for all sandboxing
|
||||
/// attributes, so this may change in the future.
|
||||
@@ -33,15 +33,15 @@ pub enum StdioPolicy {
|
||||
/// ensuring the args and environment variables used to create the `Command`
|
||||
/// (and `Child`) honor the configuration.
|
||||
///
|
||||
/// For now, we take `SandboxPolicy` as a parameter to spawn_child() because
|
||||
/// we need to determine whether to set the
|
||||
/// For now, we take `NetworkSandboxPolicy` as a parameter to spawn_child()
|
||||
/// because we need to determine whether to set the
|
||||
/// `CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR` environment variable.
|
||||
pub(crate) struct SpawnChildRequest<'a> {
|
||||
pub program: PathBuf,
|
||||
pub args: Vec<String>,
|
||||
pub arg0: Option<&'a str>,
|
||||
pub cwd: PathBuf,
|
||||
pub sandbox_policy: &'a SandboxPolicy,
|
||||
pub network_sandbox_policy: NetworkSandboxPolicy,
|
||||
pub network: Option<&'a NetworkProxy>,
|
||||
pub stdio_policy: StdioPolicy,
|
||||
pub env: HashMap<String, String>,
|
||||
@@ -53,14 +53,14 @@ pub(crate) async fn spawn_child_async(request: SpawnChildRequest<'_>) -> std::io
|
||||
args,
|
||||
arg0,
|
||||
cwd,
|
||||
sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
network,
|
||||
stdio_policy,
|
||||
mut env,
|
||||
} = request;
|
||||
|
||||
trace!(
|
||||
"spawn_child_async: {program:?} {args:?} {arg0:?} {cwd:?} {sandbox_policy:?} {stdio_policy:?} {env:?}"
|
||||
"spawn_child_async: {program:?} {args:?} {arg0:?} {cwd:?} {network_sandbox_policy:?} {stdio_policy:?} {env:?}"
|
||||
);
|
||||
|
||||
let mut cmd = Command::new(&program);
|
||||
@@ -74,7 +74,7 @@ pub(crate) async fn spawn_child_async(request: SpawnChildRequest<'_>) -> std::io
|
||||
cmd.env_clear();
|
||||
cmd.envs(env);
|
||||
|
||||
if !sandbox_policy.has_full_network_access() {
|
||||
if !network_sandbox_policy.is_enabled() {
|
||||
cmd.env(CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR, "1");
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ use crate::protocol::ExecCommandBeginEvent;
|
||||
use crate::protocol::ExecCommandEndEvent;
|
||||
use crate::protocol::ExecCommandSource;
|
||||
use crate::protocol::ExecCommandStatus;
|
||||
use crate::protocol::FileSystemSandboxPolicy;
|
||||
use crate::protocol::NetworkSandboxPolicy;
|
||||
use crate::protocol::SandboxPolicy;
|
||||
use crate::protocol::TurnStartedEvent;
|
||||
use crate::sandboxing::ExecRequest;
|
||||
@@ -163,6 +165,8 @@ pub(crate) async fn execute_user_shell_command(
|
||||
windows_sandbox_level: turn_context.windows_sandbox_level,
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
sandbox_policy: sandbox_policy.clone(),
|
||||
file_system_sandbox_policy: FileSystemSandboxPolicy::from(&sandbox_policy),
|
||||
network_sandbox_policy: NetworkSandboxPolicy::from(&sandbox_policy),
|
||||
justification: None,
|
||||
arg0: None,
|
||||
};
|
||||
@@ -173,7 +177,7 @@ pub(crate) async fn execute_user_shell_command(
|
||||
tx_event: session.get_tx_event(),
|
||||
});
|
||||
|
||||
let exec_result = execute_exec_env(exec_env, &sandbox_policy, stdout_stream)
|
||||
let exec_result = execute_exec_env(exec_env, stdout_stream)
|
||||
.or_cancel(&cancellation_token)
|
||||
.await;
|
||||
|
||||
|
||||
@@ -852,7 +852,7 @@ impl JsReplManager {
|
||||
.network
|
||||
.is_some();
|
||||
let sandbox_type = sandbox.select_initial(
|
||||
&turn.sandbox_policy,
|
||||
&turn.file_system_sandbox_policy,
|
||||
SandboxablePreference::Auto,
|
||||
turn.windows_sandbox_level,
|
||||
has_managed_network_requirements,
|
||||
@@ -861,6 +861,8 @@ impl JsReplManager {
|
||||
.transform(crate::sandboxing::SandboxTransformRequest {
|
||||
spec,
|
||||
policy: &turn.sandbox_policy,
|
||||
file_system_policy: &turn.file_system_sandbox_policy,
|
||||
network_policy: turn.network_sandbox_policy,
|
||||
sandbox: sandbox_type,
|
||||
enforce_managed_network: has_managed_network_requirements,
|
||||
network: None,
|
||||
|
||||
@@ -169,7 +169,7 @@ impl ToolOrchestrator {
|
||||
let initial_sandbox = match tool.sandbox_mode_for_first_attempt(req) {
|
||||
SandboxOverride::BypassSandboxFirstAttempt => crate::exec::SandboxType::None,
|
||||
SandboxOverride::NoOverride => self.sandbox.select_initial(
|
||||
&turn_ctx.sandbox_policy,
|
||||
&turn_ctx.file_system_sandbox_policy,
|
||||
tool.sandbox_preference(),
|
||||
turn_ctx.windows_sandbox_level,
|
||||
has_managed_network_requirements,
|
||||
@@ -182,6 +182,8 @@ impl ToolOrchestrator {
|
||||
let initial_attempt = SandboxAttempt {
|
||||
sandbox: initial_sandbox,
|
||||
policy: &turn_ctx.sandbox_policy,
|
||||
file_system_policy: &turn_ctx.file_system_sandbox_policy,
|
||||
network_policy: turn_ctx.network_sandbox_policy,
|
||||
enforce_managed_network: has_managed_network_requirements,
|
||||
manager: &self.sandbox,
|
||||
sandbox_cwd: &turn_ctx.cwd,
|
||||
@@ -296,6 +298,8 @@ impl ToolOrchestrator {
|
||||
let escalated_attempt = SandboxAttempt {
|
||||
sandbox: crate::exec::SandboxType::None,
|
||||
policy: &turn_ctx.sandbox_policy,
|
||||
file_system_policy: &turn_ctx.file_system_sandbox_policy,
|
||||
network_policy: turn_ctx.network_sandbox_policy,
|
||||
enforce_managed_network: has_managed_network_requirements,
|
||||
manager: &self.sandbox,
|
||||
sandbox_cwd: &turn_ctx.cwd,
|
||||
|
||||
@@ -26,7 +26,9 @@ use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::MacOsSeatbeltProfileExtensions;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use codex_protocol::protocol::FileSystemSandboxPolicy;
|
||||
use codex_protocol::protocol::NetworkPolicyRuleAction;
|
||||
use codex_protocol::protocol::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::RejectConfig;
|
||||
use codex_protocol::protocol::ReviewDecision;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
@@ -98,6 +100,8 @@ pub(super) async fn try_run_zsh_fork(
|
||||
windows_sandbox_level,
|
||||
sandbox_permissions,
|
||||
sandbox_policy,
|
||||
file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
justification,
|
||||
arg0,
|
||||
} = sandbox_exec_request;
|
||||
@@ -110,6 +114,8 @@ pub(super) async fn try_run_zsh_fork(
|
||||
command,
|
||||
cwd: sandbox_cwd,
|
||||
sandbox_policy,
|
||||
file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
sandbox,
|
||||
env: sandbox_env,
|
||||
network: sandbox_network,
|
||||
@@ -721,6 +727,8 @@ struct CoreShellCommandExecutor {
|
||||
command: Vec<String>,
|
||||
cwd: PathBuf,
|
||||
sandbox_policy: SandboxPolicy,
|
||||
file_system_sandbox_policy: FileSystemSandboxPolicy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
sandbox: SandboxType,
|
||||
env: HashMap<String, String>,
|
||||
network: Option<codex_network_proxy::NetworkProxy>,
|
||||
@@ -761,6 +769,8 @@ impl ShellCommandExecutor for CoreShellCommandExecutor {
|
||||
windows_sandbox_level: self.windows_sandbox_level,
|
||||
sandbox_permissions: self.sandbox_permissions,
|
||||
sandbox_policy: self.sandbox_policy.clone(),
|
||||
file_system_sandbox_policy: self.file_system_sandbox_policy.clone(),
|
||||
network_sandbox_policy: self.network_sandbox_policy,
|
||||
justification: self.justification.clone(),
|
||||
arg0: self.arg0.clone(),
|
||||
},
|
||||
@@ -805,6 +815,8 @@ impl ShellCommandExecutor for CoreShellCommandExecutor {
|
||||
workdir,
|
||||
env,
|
||||
&self.sandbox_policy,
|
||||
&self.file_system_sandbox_policy,
|
||||
self.network_sandbox_policy,
|
||||
None,
|
||||
self.macos_seatbelt_profile_extensions.as_ref(),
|
||||
)?,
|
||||
@@ -815,15 +827,23 @@ impl ShellCommandExecutor for CoreShellCommandExecutor {
|
||||
workdir,
|
||||
env,
|
||||
&self.sandbox_policy,
|
||||
&self.file_system_sandbox_policy,
|
||||
self.network_sandbox_policy,
|
||||
Some(permission_profile),
|
||||
None,
|
||||
)?,
|
||||
EscalationExecution::Permissions(EscalationPermissions::Permissions(permissions)) => {
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from(&permissions.sandbox_policy);
|
||||
let network_sandbox_policy =
|
||||
NetworkSandboxPolicy::from(&permissions.sandbox_policy);
|
||||
self.prepare_sandboxed_exec(
|
||||
command,
|
||||
workdir,
|
||||
env,
|
||||
&permissions.sandbox_policy,
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
None,
|
||||
permissions.macos_seatbelt_profile_extensions.as_ref(),
|
||||
)?
|
||||
@@ -835,12 +855,15 @@ impl ShellCommandExecutor for CoreShellCommandExecutor {
|
||||
}
|
||||
|
||||
impl CoreShellCommandExecutor {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn prepare_sandboxed_exec(
|
||||
&self,
|
||||
command: Vec<String>,
|
||||
workdir: &AbsolutePathBuf,
|
||||
env: HashMap<String, String>,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
additional_permissions: Option<PermissionProfile>,
|
||||
#[cfg(target_os = "macos")] macos_seatbelt_profile_extensions: Option<
|
||||
&MacOsSeatbeltProfileExtensions,
|
||||
@@ -854,7 +877,7 @@ impl CoreShellCommandExecutor {
|
||||
.ok_or_else(|| anyhow::anyhow!("prepared command must not be empty"))?;
|
||||
let sandbox_manager = crate::sandboxing::SandboxManager::new();
|
||||
let sandbox = sandbox_manager.select_initial(
|
||||
sandbox_policy,
|
||||
file_system_sandbox_policy,
|
||||
SandboxablePreference::Auto,
|
||||
self.windows_sandbox_level,
|
||||
self.network.is_some(),
|
||||
@@ -876,6 +899,8 @@ impl CoreShellCommandExecutor {
|
||||
justification: self.justification.clone(),
|
||||
},
|
||||
policy: sandbox_policy,
|
||||
file_system_policy: file_system_sandbox_policy,
|
||||
network_policy: network_sandbox_policy,
|
||||
sandbox,
|
||||
enforce_managed_network: self.network.is_some(),
|
||||
network: self.network.as_ref(),
|
||||
|
||||
@@ -426,6 +426,10 @@ async fn prepare_escalated_exec_turn_default_preserves_macos_seatbelt_extensions
|
||||
network: None,
|
||||
sandbox: SandboxType::None,
|
||||
sandbox_policy: SandboxPolicy::new_read_only_policy(),
|
||||
file_system_sandbox_policy: FileSystemSandboxPolicy::from(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
),
|
||||
network_sandbox_policy: NetworkSandboxPolicy::Restricted,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
justification: None,
|
||||
@@ -476,6 +480,8 @@ async fn prepare_escalated_exec_permissions_preserve_macos_seatbelt_extensions()
|
||||
network: None,
|
||||
sandbox: SandboxType::None,
|
||||
sandbox_policy: SandboxPolicy::DangerFullAccess,
|
||||
file_system_sandbox_policy: FileSystemSandboxPolicy::from(&SandboxPolicy::DangerFullAccess),
|
||||
network_sandbox_policy: NetworkSandboxPolicy::Enabled,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
justification: None,
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
use crate::codex::Session;
|
||||
use crate::codex::TurnContext;
|
||||
use crate::error::CodexErr;
|
||||
use crate::protocol::FileSystemSandboxPolicy;
|
||||
use crate::protocol::NetworkSandboxPolicy;
|
||||
use crate::protocol::SandboxPolicy;
|
||||
use crate::sandboxing::CommandSpec;
|
||||
use crate::sandboxing::SandboxManager;
|
||||
@@ -318,6 +320,8 @@ pub(crate) trait ToolRuntime<Req, Out>: Approvable<Req> + Sandboxable {
|
||||
pub(crate) struct SandboxAttempt<'a> {
|
||||
pub sandbox: crate::exec::SandboxType,
|
||||
pub policy: &'a crate::protocol::SandboxPolicy,
|
||||
pub file_system_policy: &'a FileSystemSandboxPolicy,
|
||||
pub network_policy: NetworkSandboxPolicy,
|
||||
pub enforce_managed_network: bool,
|
||||
pub(crate) manager: &'a SandboxManager,
|
||||
pub(crate) sandbox_cwd: &'a Path,
|
||||
@@ -336,6 +340,8 @@ impl<'a> SandboxAttempt<'a> {
|
||||
.transform(crate::sandboxing::SandboxTransformRequest {
|
||||
spec,
|
||||
policy: self.policy,
|
||||
file_system_policy: self.file_system_policy,
|
||||
network_policy: self.network_policy,
|
||||
sandbox: self.sandbox,
|
||||
enforce_managed_network: self.enforce_managed_network,
|
||||
network,
|
||||
|
||||
@@ -10,6 +10,8 @@ use codex_core::exec::process_exec_tool_call;
|
||||
use codex_core::sandboxing::SandboxPermissions;
|
||||
use codex_core::spawn::CODEX_SANDBOX_ENV_VAR;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::protocol::FileSystemSandboxPolicy;
|
||||
use codex_protocol::protocol::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use tempfile::TempDir;
|
||||
|
||||
@@ -45,7 +47,17 @@ async fn run_test_cmd(tmp: TempDir, cmd: Vec<&str>) -> Result<ExecToolCallOutput
|
||||
|
||||
let policy = SandboxPolicy::new_read_only_policy();
|
||||
|
||||
process_exec_tool_call(params, &policy, tmp.path(), &None, false, None).await
|
||||
process_exec_tool_call(
|
||||
params,
|
||||
&policy,
|
||||
&FileSystemSandboxPolicy::from(&policy),
|
||||
NetworkSandboxPolicy::from(&policy),
|
||||
tmp.path(),
|
||||
&None,
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Command succeeds with exit code 0 normally
|
||||
|
||||
@@ -5,6 +5,7 @@ use codex_protocol::protocol::EventMsg;
|
||||
use codex_protocol::protocol::ExecCommandEndEvent;
|
||||
use codex_protocol::protocol::ExecCommandSource;
|
||||
use codex_protocol::protocol::ExecOutputStream;
|
||||
use codex_protocol::protocol::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::Op;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_protocol::protocol::TurnAbortReason;
|
||||
@@ -23,6 +24,7 @@ use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::wait_for_event;
|
||||
use core_test_support::wait_for_event_match;
|
||||
use core_test_support::wait_for_event_with_timeout;
|
||||
use pretty_assertions::assert_eq;
|
||||
use regex_lite::escape;
|
||||
use std::path::PathBuf;
|
||||
use tempfile::TempDir;
|
||||
@@ -328,6 +330,35 @@ async fn user_shell_command_history_is_persisted_and_shared_with_model() -> anyh
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn user_shell_command_does_not_set_network_sandbox_env_var() -> anyhow::Result<()> {
|
||||
let server = responses::start_mock_server().await;
|
||||
let mut builder = core_test_support::test_codex::test_codex().with_config(|config| {
|
||||
config.permissions.network_sandbox_policy = NetworkSandboxPolicy::Restricted;
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
#[cfg(windows)]
|
||||
let command = r#"$val = $env:CODEX_SANDBOX_NETWORK_DISABLED; if ([string]::IsNullOrEmpty($val)) { $val = 'not-set' } ; [System.Console]::Write($val)"#.to_string();
|
||||
#[cfg(not(windows))]
|
||||
let command =
|
||||
r#"sh -c "printf '%s' \"${CODEX_SANDBOX_NETWORK_DISABLED:-not-set}\"""#.to_string();
|
||||
|
||||
test.codex
|
||||
.submit(Op::RunUserShellCommand { command })
|
||||
.await?;
|
||||
|
||||
let end_event = wait_for_event_match(&test.codex, |ev| match ev {
|
||||
EventMsg::ExecCommandEnd(event) => Some(event.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.await;
|
||||
assert_eq!(end_event.exit_code, 0);
|
||||
assert_eq!(end_event.stdout.trim(), "not-set");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
#[cfg(not(target_os = "windows"))] // TODO: unignore on windows
|
||||
async fn user_shell_command_output_is_truncated_in_history() -> anyhow::Result<()> {
|
||||
|
||||
@@ -9,6 +9,8 @@ use codex_core::exec::process_exec_tool_call;
|
||||
use codex_core::exec_env::create_env;
|
||||
use codex_core::sandboxing::SandboxPermissions;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::protocol::FileSystemSandboxPolicy;
|
||||
use codex_protocol::protocol::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -102,6 +104,8 @@ async fn run_cmd_result_with_writable_roots(
|
||||
process_exec_tool_call(
|
||||
params,
|
||||
&sandbox_policy,
|
||||
&FileSystemSandboxPolicy::from(&sandbox_policy),
|
||||
NetworkSandboxPolicy::from(&sandbox_policy),
|
||||
sandbox_cwd.as_path(),
|
||||
&codex_linux_sandbox_exe,
|
||||
use_bwrap_sandbox,
|
||||
@@ -333,6 +337,8 @@ async fn assert_network_blocked(cmd: &[&str]) {
|
||||
let result = process_exec_tool_call(
|
||||
params,
|
||||
&sandbox_policy,
|
||||
&FileSystemSandboxPolicy::from(&sandbox_policy),
|
||||
NetworkSandboxPolicy::from(&sandbox_policy),
|
||||
sandbox_cwd.as_path(),
|
||||
&codex_linux_sandbox_exe,
|
||||
false,
|
||||
|
||||
Reference in New Issue
Block a user