mirror of
https://github.com/openai/codex.git
synced 2026-11-02 00:18:52 +00:00
refactor: make bubblewrap the default Linux sandbox (#13996)
## Summary - make bubblewrap the default Linux sandbox and keep `use_legacy_landlock` as the only override - remove `use_linux_sandbox_bwrap` from feature, config, schema, and docs surfaces - update Linux sandbox selection, CLI/config plumbing, and related tests/docs to match the new default - fold in the follow-up CI fixes for request-permissions responses and Linux read-only sandbox error text
This commit is contained in:
@@ -1290,9 +1290,7 @@ impl Session {
|
||||
cwd.clone(),
|
||||
session_configuration.sandbox_policy.get(),
|
||||
session_configuration.windows_sandbox_level,
|
||||
per_turn_config
|
||||
.features
|
||||
.enabled(Feature::UseLinuxSandboxBwrap),
|
||||
per_turn_config.features.use_legacy_landlock(),
|
||||
));
|
||||
let (current_date, timezone) = local_time_context();
|
||||
TurnContext {
|
||||
@@ -1802,7 +1800,7 @@ impl Session {
|
||||
sandbox_policy: session_configuration.sandbox_policy.get().clone(),
|
||||
codex_linux_sandbox_exe: config.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: session_configuration.cwd.clone(),
|
||||
use_linux_sandbox_bwrap: config.features.enabled(Feature::UseLinuxSandboxBwrap),
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
};
|
||||
let mut required_mcp_servers: Vec<String> = mcp_servers
|
||||
.iter()
|
||||
@@ -2275,9 +2273,7 @@ impl Session {
|
||||
sandbox_policy: per_turn_config.permissions.sandbox_policy.get().clone(),
|
||||
codex_linux_sandbox_exe: per_turn_config.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: per_turn_config.cwd.clone(),
|
||||
use_linux_sandbox_bwrap: per_turn_config
|
||||
.features
|
||||
.enabled(Feature::UseLinuxSandboxBwrap),
|
||||
use_legacy_landlock: per_turn_config.features.use_legacy_landlock(),
|
||||
};
|
||||
if let Err(e) = self
|
||||
.services
|
||||
@@ -3938,7 +3934,7 @@ impl Session {
|
||||
sandbox_policy: turn_context.sandbox_policy.get().clone(),
|
||||
codex_linux_sandbox_exe: turn_context.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: turn_context.cwd.clone(),
|
||||
use_linux_sandbox_bwrap: turn_context.features.enabled(Feature::UseLinuxSandboxBwrap),
|
||||
use_legacy_landlock: turn_context.features.use_legacy_landlock(),
|
||||
};
|
||||
{
|
||||
let mut guard = self.services.mcp_startup_cancellation_token.lock().await;
|
||||
@@ -5215,9 +5211,7 @@ async fn spawn_review_thread(
|
||||
parent_turn_context.cwd.clone(),
|
||||
parent_turn_context.sandbox_policy.get(),
|
||||
parent_turn_context.windows_sandbox_level,
|
||||
parent_turn_context
|
||||
.features
|
||||
.enabled(Feature::UseLinuxSandboxBwrap),
|
||||
parent_turn_context.features.use_legacy_landlock(),
|
||||
));
|
||||
|
||||
let review_turn_context = TurnContext {
|
||||
|
||||
@@ -31,7 +31,6 @@ use crate::config::types::AppsConfigToml;
|
||||
use crate::default_client::create_client;
|
||||
use crate::default_client::is_first_party_chat_originator;
|
||||
use crate::default_client::originator;
|
||||
use crate::features::Feature;
|
||||
use crate::mcp::CODEX_APPS_MCP_SERVER_NAME;
|
||||
use crate::mcp::McpManager;
|
||||
use crate::mcp::ToolPluginProvenance;
|
||||
@@ -203,7 +202,7 @@ pub async fn list_accessible_connectors_from_mcp_tools_with_options_and_status(
|
||||
sandbox_policy: SandboxPolicy::new_read_only_policy(),
|
||||
codex_linux_sandbox_exe: config.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: env::current_dir().unwrap_or_else(|_| PathBuf::from("/")),
|
||||
use_linux_sandbox_bwrap: config.features.enabled(Feature::UseLinuxSandboxBwrap),
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
};
|
||||
|
||||
let (mcp_connection_manager, cancel_token) = McpConnectionManager::new(
|
||||
|
||||
@@ -185,7 +185,7 @@ pub async fn process_exec_tool_call(
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
sandbox_cwd: &Path,
|
||||
codex_linux_sandbox_exe: &Option<PathBuf>,
|
||||
use_linux_sandbox_bwrap: bool,
|
||||
use_legacy_landlock: bool,
|
||||
stdout_stream: Option<StdoutStream>,
|
||||
) -> Result<ExecToolCallOutput> {
|
||||
let exec_req = build_exec_request(
|
||||
@@ -195,7 +195,7 @@ pub async fn process_exec_tool_call(
|
||||
network_sandbox_policy,
|
||||
sandbox_cwd,
|
||||
codex_linux_sandbox_exe,
|
||||
use_linux_sandbox_bwrap,
|
||||
use_legacy_landlock,
|
||||
)?;
|
||||
|
||||
// Route through the sandboxing module for a single, unified execution path.
|
||||
@@ -211,7 +211,7 @@ pub fn build_exec_request(
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
sandbox_cwd: &Path,
|
||||
codex_linux_sandbox_exe: &Option<PathBuf>,
|
||||
use_linux_sandbox_bwrap: bool,
|
||||
use_legacy_landlock: bool,
|
||||
) -> Result<ExecRequest> {
|
||||
let windows_sandbox_level = params.windows_sandbox_level;
|
||||
let enforce_managed_network = params.network.is_some();
|
||||
@@ -269,7 +269,7 @@ pub fn build_exec_request(
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: codex_linux_sandbox_exe.as_ref(),
|
||||
use_linux_sandbox_bwrap,
|
||||
use_legacy_landlock,
|
||||
windows_sandbox_level,
|
||||
})
|
||||
.map_err(CodexErr::from)?;
|
||||
|
||||
@@ -108,8 +108,9 @@ pub enum Feature {
|
||||
WebSearchCached,
|
||||
/// Legacy search-tool feature flag kept for backward compatibility.
|
||||
SearchTool,
|
||||
/// Use the bubblewrap-based Linux sandbox pipeline.
|
||||
UseLinuxSandboxBwrap,
|
||||
/// Use the legacy Landlock Linux sandbox fallback instead of the default
|
||||
/// bubblewrap pipeline.
|
||||
UseLegacyLandlock,
|
||||
/// Allow the model to request approval and propose exec rules.
|
||||
RequestRule,
|
||||
/// Enable Windows sandbox (restricted token) on Windows.
|
||||
@@ -284,6 +285,10 @@ impl Features {
|
||||
self.enabled(Feature::Apps) && auth.is_some_and(CodexAuth::is_chatgpt_auth)
|
||||
}
|
||||
|
||||
pub fn use_legacy_landlock(&self) -> bool {
|
||||
self.enabled(Feature::UseLegacyLandlock)
|
||||
}
|
||||
|
||||
pub fn enable(&mut self, f: Feature) -> &mut Self {
|
||||
self.enabled.insert(f);
|
||||
self
|
||||
@@ -636,16 +641,9 @@ pub const FEATURES: &[FeatureSpec] = &[
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::UseLinuxSandboxBwrap,
|
||||
key: "use_linux_sandbox_bwrap",
|
||||
#[cfg(target_os = "linux")]
|
||||
stage: Stage::Experimental {
|
||||
name: "Bubblewrap sandbox",
|
||||
menu_description: "Try the new linux sandbox based on bubblewrap.",
|
||||
announcement: "NEW: Linux bubblewrap sandbox offers stronger filesystem and network controls than Landlock alone, including keeping .git and .codex read-only inside writable workspaces. Enable it in /experimental and restart Codex to try it.",
|
||||
},
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
stage: Stage::UnderDevelopment,
|
||||
id: Feature::UseLegacyLandlock,
|
||||
key: "use_legacy_landlock",
|
||||
stage: Stage::Stable,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
@@ -932,24 +930,10 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn use_linux_sandbox_bwrap_is_experimental_on_linux() {
|
||||
assert!(matches!(
|
||||
Feature::UseLinuxSandboxBwrap.stage(),
|
||||
Stage::Experimental { .. }
|
||||
));
|
||||
assert_eq!(Feature::UseLinuxSandboxBwrap.default_enabled(), false);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[test]
|
||||
fn use_linux_sandbox_bwrap_is_under_development_off_linux() {
|
||||
assert_eq!(
|
||||
Feature::UseLinuxSandboxBwrap.stage(),
|
||||
Stage::UnderDevelopment
|
||||
);
|
||||
assert_eq!(Feature::UseLinuxSandboxBwrap.default_enabled(), false);
|
||||
fn use_legacy_landlock_is_stable_and_disabled_by_default() {
|
||||
assert_eq!(Feature::UseLegacyLandlock.stage(), Stage::Stable);
|
||||
assert_eq!(Feature::UseLegacyLandlock.default_enabled(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -11,7 +11,7 @@ use std::path::PathBuf;
|
||||
use tokio::process::Child;
|
||||
|
||||
/// Spawn a shell tool command under the Linux sandbox helper
|
||||
/// (codex-linux-sandbox), which currently uses bubblewrap for filesystem
|
||||
/// (codex-linux-sandbox), which defaults to bubblewrap for filesystem
|
||||
/// isolation plus seccomp for network restrictions.
|
||||
///
|
||||
/// Unlike macOS Seatbelt where we directly embed the policy text, the Linux
|
||||
@@ -25,7 +25,7 @@ pub async fn spawn_command_under_linux_sandbox<P>(
|
||||
command_cwd: PathBuf,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
sandbox_policy_cwd: &Path,
|
||||
use_bwrap_sandbox: bool,
|
||||
use_legacy_landlock: bool,
|
||||
stdio_policy: StdioPolicy,
|
||||
network: Option<&NetworkProxy>,
|
||||
env: HashMap<String, String>,
|
||||
@@ -42,7 +42,7 @@ where
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
sandbox_policy_cwd,
|
||||
use_bwrap_sandbox,
|
||||
use_legacy_landlock,
|
||||
allow_network_for_proxy(false),
|
||||
);
|
||||
let arg0 = Some("codex-linux-sandbox");
|
||||
@@ -69,7 +69,7 @@ pub(crate) fn allow_network_for_proxy(enforce_managed_network: bool) -> bool {
|
||||
/// Converts the sandbox policies into the CLI invocation for
|
||||
/// `codex-linux-sandbox`.
|
||||
///
|
||||
/// The helper performs the actual sandboxing (bubblewrap + seccomp) after
|
||||
/// The helper performs the actual sandboxing (bubblewrap by default + seccomp) after
|
||||
/// parsing these arguments. Policy JSON flags are emitted before helper feature
|
||||
/// flags so the argv order matches the helper's CLI shape. See
|
||||
/// `docs/linux_sandbox.md` for the Linux semantics.
|
||||
@@ -80,7 +80,7 @@ pub(crate) fn create_linux_sandbox_command_args_for_policies(
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
sandbox_policy_cwd: &Path,
|
||||
use_bwrap_sandbox: bool,
|
||||
use_legacy_landlock: bool,
|
||||
allow_network_for_proxy: bool,
|
||||
) -> Vec<String> {
|
||||
let sandbox_policy_json = serde_json::to_string(sandbox_policy)
|
||||
@@ -104,8 +104,8 @@ pub(crate) fn create_linux_sandbox_command_args_for_policies(
|
||||
"--network-sandbox-policy".to_string(),
|
||||
network_policy_json,
|
||||
];
|
||||
if use_bwrap_sandbox {
|
||||
linux_cmd.push("--use-bwrap-sandbox".to_string());
|
||||
if use_legacy_landlock {
|
||||
linux_cmd.push("--use-legacy-landlock".to_string());
|
||||
}
|
||||
if allow_network_for_proxy {
|
||||
linux_cmd.push("--allow-network-for-proxy".to_string());
|
||||
@@ -121,7 +121,7 @@ pub(crate) fn create_linux_sandbox_command_args_for_policies(
|
||||
pub(crate) fn create_linux_sandbox_command_args(
|
||||
command: Vec<String>,
|
||||
sandbox_policy_cwd: &Path,
|
||||
use_bwrap_sandbox: bool,
|
||||
use_legacy_landlock: bool,
|
||||
allow_network_for_proxy: bool,
|
||||
) -> Vec<String> {
|
||||
let sandbox_policy_cwd = sandbox_policy_cwd
|
||||
@@ -130,8 +130,8 @@ pub(crate) fn create_linux_sandbox_command_args(
|
||||
.to_string();
|
||||
|
||||
let mut linux_cmd: Vec<String> = vec!["--sandbox-policy-cwd".to_string(), sandbox_policy_cwd];
|
||||
if use_bwrap_sandbox {
|
||||
linux_cmd.push("--use-bwrap-sandbox".to_string());
|
||||
if use_legacy_landlock {
|
||||
linux_cmd.push("--use-legacy-landlock".to_string());
|
||||
}
|
||||
if allow_network_for_proxy {
|
||||
linux_cmd.push("--allow-network-for-proxy".to_string());
|
||||
@@ -153,20 +153,20 @@ mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn bwrap_flags_are_feature_gated() {
|
||||
fn legacy_landlock_flag_is_included_when_requested() {
|
||||
let command = vec!["/bin/true".to_string()];
|
||||
let cwd = Path::new("/tmp");
|
||||
|
||||
let with_bwrap = create_linux_sandbox_command_args(command.clone(), cwd, true, false);
|
||||
let default_bwrap = create_linux_sandbox_command_args(command.clone(), cwd, false, false);
|
||||
assert_eq!(
|
||||
with_bwrap.contains(&"--use-bwrap-sandbox".to_string()),
|
||||
true
|
||||
default_bwrap.contains(&"--use-legacy-landlock".to_string()),
|
||||
false
|
||||
);
|
||||
|
||||
let without_bwrap = create_linux_sandbox_command_args(command, cwd, false, false);
|
||||
let legacy_landlock = create_linux_sandbox_command_args(command, cwd, true, false);
|
||||
assert_eq!(
|
||||
without_bwrap.contains(&"--use-bwrap-sandbox".to_string()),
|
||||
false
|
||||
legacy_landlock.contains(&"--use-legacy-landlock".to_string()),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@ pub async fn collect_mcp_snapshot(config: &Config) -> McpListToolsResponseEvent
|
||||
sandbox_policy: SandboxPolicy::new_read_only_policy(),
|
||||
codex_linux_sandbox_exe: config.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: env::current_dir().unwrap_or_else(|_| PathBuf::from("/")),
|
||||
use_linux_sandbox_bwrap: config.features.enabled(Feature::UseLinuxSandboxBwrap),
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
};
|
||||
|
||||
let (mcp_connection_manager, cancel_token) = McpConnectionManager::new(
|
||||
|
||||
@@ -591,7 +591,7 @@ pub struct SandboxState {
|
||||
pub codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
pub sandbox_cwd: PathBuf,
|
||||
#[serde(default)]
|
||||
pub use_linux_sandbox_bwrap: bool,
|
||||
pub use_legacy_landlock: bool,
|
||||
}
|
||||
|
||||
/// A thin wrapper around a set of running [`RmcpClient`] instances.
|
||||
|
||||
@@ -6,7 +6,7 @@ use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
pub(crate) fn sandbox_tag(
|
||||
policy: &SandboxPolicy,
|
||||
windows_sandbox_level: WindowsSandboxLevel,
|
||||
use_linux_sandbox_bwrap: bool,
|
||||
use_legacy_landlock: bool,
|
||||
) -> &'static str {
|
||||
if matches!(policy, SandboxPolicy::DangerFullAccess) {
|
||||
return "none";
|
||||
@@ -18,7 +18,7 @@ pub(crate) fn sandbox_tag(
|
||||
{
|
||||
return "windows_elevated";
|
||||
}
|
||||
if cfg!(target_os = "linux") && use_linux_sandbox_bwrap {
|
||||
if cfg!(target_os = "linux") && !use_legacy_landlock {
|
||||
return "linux_bubblewrap";
|
||||
}
|
||||
|
||||
@@ -38,33 +38,33 @@ mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn danger_full_access_is_untagged_even_when_bubblewrap_is_enabled() {
|
||||
fn danger_full_access_is_untagged_even_when_bubblewrap_is_default() {
|
||||
let actual = sandbox_tag(
|
||||
&SandboxPolicy::DangerFullAccess,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert_eq!(actual, "none");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn external_sandbox_keeps_external_tag_when_bubblewrap_is_enabled() {
|
||||
fn external_sandbox_keeps_external_tag_when_bubblewrap_is_default() {
|
||||
let actual = sandbox_tag(
|
||||
&SandboxPolicy::ExternalSandbox {
|
||||
network_access: NetworkAccess::Enabled,
|
||||
},
|
||||
WindowsSandboxLevel::Disabled,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert_eq!(actual, "external");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bubblewrap_feature_sets_distinct_linux_tag() {
|
||||
fn bubblewrap_default_sets_distinct_linux_tag() {
|
||||
let actual = sandbox_tag(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
WindowsSandboxLevel::Disabled,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
let expected = if cfg!(target_os = "linux") {
|
||||
"linux_bubblewrap"
|
||||
|
||||
@@ -94,7 +94,7 @@ pub(crate) struct SandboxTransformRequest<'a> {
|
||||
#[cfg(target_os = "macos")]
|
||||
pub macos_seatbelt_profile_extensions: Option<&'a MacOsSeatbeltProfileExtensions>,
|
||||
pub codex_linux_sandbox_exe: Option<&'a PathBuf>,
|
||||
pub use_linux_sandbox_bwrap: bool,
|
||||
pub use_legacy_landlock: bool,
|
||||
pub windows_sandbox_level: WindowsSandboxLevel,
|
||||
}
|
||||
|
||||
@@ -571,7 +571,7 @@ impl SandboxManager {
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions,
|
||||
codex_linux_sandbox_exe,
|
||||
use_linux_sandbox_bwrap,
|
||||
use_legacy_landlock,
|
||||
windows_sandbox_level,
|
||||
} = request;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
@@ -653,7 +653,7 @@ impl SandboxManager {
|
||||
&effective_file_system_policy,
|
||||
effective_network_policy,
|
||||
sandbox_policy_cwd,
|
||||
use_linux_sandbox_bwrap,
|
||||
use_legacy_landlock,
|
||||
allow_proxy_network,
|
||||
);
|
||||
let mut full_command = Vec::with_capacity(1 + args.len());
|
||||
@@ -886,7 +886,7 @@ mod tests {
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_linux_sandbox_bwrap: false,
|
||||
use_legacy_landlock: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
})
|
||||
.expect("transform");
|
||||
@@ -1219,7 +1219,7 @@ mod tests {
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_linux_sandbox_bwrap: false,
|
||||
use_legacy_landlock: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
})
|
||||
.expect("transform");
|
||||
@@ -1291,7 +1291,7 @@ mod tests {
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_linux_sandbox_bwrap: false,
|
||||
use_legacy_landlock: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
})
|
||||
.expect("transform");
|
||||
|
||||
@@ -884,9 +884,7 @@ impl JsReplManager {
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: turn.codex_linux_sandbox_exe.as_ref(),
|
||||
use_linux_sandbox_bwrap: turn
|
||||
.features
|
||||
.enabled(crate::features::Feature::UseLinuxSandboxBwrap),
|
||||
use_legacy_landlock: turn.features.use_legacy_landlock(),
|
||||
windows_sandbox_level: turn.windows_sandbox_level,
|
||||
})
|
||||
.map_err(|err| format!("failed to configure sandbox for js_repl: {err}"))?;
|
||||
|
||||
@@ -9,7 +9,6 @@ caching).
|
||||
use crate::error::CodexErr;
|
||||
use crate::error::SandboxErr;
|
||||
use crate::exec::ExecToolCallOutput;
|
||||
use crate::features::Feature;
|
||||
use crate::guardian::GUARDIAN_REJECTION_MESSAGE;
|
||||
use crate::guardian::routes_approval_to_guardian;
|
||||
use crate::network_policy_decision::network_approval_context_from_payload;
|
||||
@@ -186,7 +185,7 @@ impl ToolOrchestrator {
|
||||
|
||||
// Platform-specific flag gating is handled by SandboxManager::select_initial
|
||||
// via crate::safety::get_platform_sandbox(..).
|
||||
let use_linux_sandbox_bwrap = turn_ctx.features.enabled(Feature::UseLinuxSandboxBwrap);
|
||||
let use_legacy_landlock = turn_ctx.features.use_legacy_landlock();
|
||||
let initial_attempt = SandboxAttempt {
|
||||
sandbox: initial_sandbox,
|
||||
policy: &turn_ctx.sandbox_policy,
|
||||
@@ -196,7 +195,7 @@ impl ToolOrchestrator {
|
||||
manager: &self.sandbox,
|
||||
sandbox_cwd: &turn_ctx.cwd,
|
||||
codex_linux_sandbox_exe: turn_ctx.codex_linux_sandbox_exe.as_ref(),
|
||||
use_linux_sandbox_bwrap,
|
||||
use_legacy_landlock,
|
||||
windows_sandbox_level: turn_ctx.windows_sandbox_level,
|
||||
};
|
||||
|
||||
@@ -318,7 +317,7 @@ impl ToolOrchestrator {
|
||||
manager: &self.sandbox,
|
||||
sandbox_cwd: &turn_ctx.cwd,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_linux_sandbox_bwrap,
|
||||
use_legacy_landlock,
|
||||
windows_sandbox_level: turn_ctx.windows_sandbox_level,
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::client_common::tools::ToolSpec;
|
||||
use crate::features::Feature;
|
||||
use crate::function_tool::FunctionCallError;
|
||||
use crate::memories::usage::emit_metric_for_tool_read;
|
||||
use crate::protocol::SandboxPolicy;
|
||||
@@ -174,10 +173,7 @@ impl ToolRegistry {
|
||||
sandbox_tag(
|
||||
&invocation.turn.sandbox_policy,
|
||||
invocation.turn.windows_sandbox_level,
|
||||
invocation
|
||||
.turn
|
||||
.features
|
||||
.enabled(Feature::UseLinuxSandboxBwrap),
|
||||
invocation.turn.features.use_legacy_landlock(),
|
||||
),
|
||||
),
|
||||
(
|
||||
@@ -505,7 +501,7 @@ async fn dispatch_after_tool_use_hook(
|
||||
sandbox: sandbox_tag(
|
||||
&turn.sandbox_policy,
|
||||
turn.windows_sandbox_level,
|
||||
turn.features.enabled(Feature::UseLinuxSandboxBwrap),
|
||||
turn.features.use_legacy_landlock(),
|
||||
)
|
||||
.to_string(),
|
||||
sandbox_policy: sandbox_policy_tag(&turn.sandbox_policy).to_string(),
|
||||
|
||||
@@ -146,7 +146,7 @@ pub(super) async fn try_run_zsh_fork(
|
||||
.macos_seatbelt_profile_extensions
|
||||
.clone(),
|
||||
codex_linux_sandbox_exe: ctx.turn.codex_linux_sandbox_exe.clone(),
|
||||
use_linux_sandbox_bwrap: ctx.turn.features.enabled(Feature::UseLinuxSandboxBwrap),
|
||||
use_legacy_landlock: ctx.turn.features.use_legacy_landlock(),
|
||||
};
|
||||
let main_execve_wrapper_exe = ctx
|
||||
.session
|
||||
@@ -258,7 +258,7 @@ pub(crate) async fn prepare_unified_exec_zsh_fork(
|
||||
.macos_seatbelt_profile_extensions
|
||||
.clone(),
|
||||
codex_linux_sandbox_exe: ctx.turn.codex_linux_sandbox_exe.clone(),
|
||||
use_linux_sandbox_bwrap: ctx.turn.features.enabled(Feature::UseLinuxSandboxBwrap),
|
||||
use_legacy_landlock: ctx.turn.features.use_legacy_landlock(),
|
||||
};
|
||||
let main_execve_wrapper_exe = ctx
|
||||
.session
|
||||
@@ -855,7 +855,7 @@ struct CoreShellCommandExecutor {
|
||||
#[cfg_attr(not(target_os = "macos"), allow(dead_code))]
|
||||
macos_seatbelt_profile_extensions: Option<MacOsSeatbeltProfileExtensions>,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
use_linux_sandbox_bwrap: bool,
|
||||
use_legacy_landlock: bool,
|
||||
}
|
||||
|
||||
struct PrepareSandboxedExecParams<'a> {
|
||||
@@ -1052,7 +1052,7 @@ impl CoreShellCommandExecutor {
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions,
|
||||
codex_linux_sandbox_exe: self.codex_linux_sandbox_exe.as_ref(),
|
||||
use_linux_sandbox_bwrap: self.use_linux_sandbox_bwrap,
|
||||
use_legacy_landlock: self.use_legacy_landlock,
|
||||
windows_sandbox_level: self.windows_sandbox_level,
|
||||
})?;
|
||||
if let Some(network) = exec_request.network.as_ref() {
|
||||
|
||||
@@ -611,7 +611,7 @@ async fn prepare_escalated_exec_turn_default_preserves_macos_seatbelt_extensions
|
||||
..Default::default()
|
||||
}),
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_linux_sandbox_bwrap: false,
|
||||
use_legacy_landlock: false,
|
||||
};
|
||||
|
||||
let prepared = executor
|
||||
@@ -660,7 +660,7 @@ async fn prepare_escalated_exec_permissions_preserve_macos_seatbelt_extensions()
|
||||
sandbox_policy_cwd: cwd.to_path_buf(),
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_linux_sandbox_bwrap: false,
|
||||
use_legacy_landlock: false,
|
||||
};
|
||||
|
||||
let permissions = Permissions {
|
||||
@@ -737,7 +737,7 @@ async fn prepare_escalated_exec_permission_profile_unions_turn_and_requested_mac
|
||||
..Default::default()
|
||||
}),
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_linux_sandbox_bwrap: false,
|
||||
use_legacy_landlock: false,
|
||||
};
|
||||
|
||||
let prepared = executor
|
||||
|
||||
@@ -330,7 +330,7 @@ pub(crate) struct SandboxAttempt<'a> {
|
||||
pub(crate) manager: &'a SandboxManager,
|
||||
pub(crate) sandbox_cwd: &'a Path,
|
||||
pub codex_linux_sandbox_exe: Option<&'a std::path::PathBuf>,
|
||||
pub use_linux_sandbox_bwrap: bool,
|
||||
pub use_legacy_landlock: bool,
|
||||
pub windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel,
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ impl<'a> SandboxAttempt<'a> {
|
||||
#[cfg(target_os = "macos")]
|
||||
macos_seatbelt_profile_extensions: None,
|
||||
codex_linux_sandbox_exe: self.codex_linux_sandbox_exe,
|
||||
use_linux_sandbox_bwrap: self.use_linux_sandbox_bwrap,
|
||||
use_legacy_landlock: self.use_legacy_landlock,
|
||||
windows_sandbox_level: self.windows_sandbox_level,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -132,16 +132,11 @@ impl TurnMetadataState {
|
||||
cwd: PathBuf,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
windows_sandbox_level: WindowsSandboxLevel,
|
||||
use_linux_sandbox_bwrap: bool,
|
||||
use_legacy_landlock: bool,
|
||||
) -> Self {
|
||||
let repo_root = get_git_repo_root(&cwd).map(|root| root.to_string_lossy().into_owned());
|
||||
let sandbox = Some(
|
||||
sandbox_tag(
|
||||
sandbox_policy,
|
||||
windows_sandbox_level,
|
||||
use_linux_sandbox_bwrap,
|
||||
)
|
||||
.to_string(),
|
||||
sandbox_tag(sandbox_policy, windows_sandbox_level, use_legacy_landlock).to_string(),
|
||||
);
|
||||
let base_metadata = build_turn_metadata_bag(Some(turn_id), sandbox, None, None);
|
||||
let base_header = base_metadata
|
||||
@@ -300,19 +295,19 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn turn_metadata_state_respects_linux_bubblewrap_toggle() {
|
||||
fn turn_metadata_state_respects_legacy_landlock_flag() {
|
||||
let temp_dir = TempDir::new().expect("temp dir");
|
||||
let cwd = temp_dir.path().to_path_buf();
|
||||
let sandbox_policy = SandboxPolicy::new_read_only_policy();
|
||||
|
||||
let without_bubblewrap = TurnMetadataState::new(
|
||||
let default_bubblewrap = TurnMetadataState::new(
|
||||
"turn-a".to_string(),
|
||||
cwd.clone(),
|
||||
&sandbox_policy,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
false,
|
||||
);
|
||||
let with_bubblewrap = TurnMetadataState::new(
|
||||
let legacy_landlock = TurnMetadataState::new(
|
||||
"turn-b".to_string(),
|
||||
cwd,
|
||||
&sandbox_policy,
|
||||
@@ -320,30 +315,33 @@ mod tests {
|
||||
true,
|
||||
);
|
||||
|
||||
let without_bubblewrap_header = without_bubblewrap
|
||||
let default_bubblewrap_header = default_bubblewrap
|
||||
.current_header_value()
|
||||
.expect("without_bubblewrap_header");
|
||||
let with_bubblewrap_header = with_bubblewrap
|
||||
.expect("default_bubblewrap_header");
|
||||
let legacy_landlock_header = legacy_landlock
|
||||
.current_header_value()
|
||||
.expect("with_bubblewrap_header");
|
||||
.expect("legacy_landlock_header");
|
||||
|
||||
let without_bubblewrap_json: Value =
|
||||
serde_json::from_str(&without_bubblewrap_header).expect("without_bubblewrap_json");
|
||||
let with_bubblewrap_json: Value =
|
||||
serde_json::from_str(&with_bubblewrap_header).expect("with_bubblewrap_json");
|
||||
let default_bubblewrap_json: Value =
|
||||
serde_json::from_str(&default_bubblewrap_header).expect("default_bubblewrap_json");
|
||||
let legacy_landlock_json: Value =
|
||||
serde_json::from_str(&legacy_landlock_header).expect("legacy_landlock_json");
|
||||
|
||||
let without_bubblewrap_sandbox = without_bubblewrap_json
|
||||
let default_bubblewrap_sandbox = default_bubblewrap_json
|
||||
.get("sandbox")
|
||||
.and_then(Value::as_str);
|
||||
let with_bubblewrap_sandbox = with_bubblewrap_json.get("sandbox").and_then(Value::as_str);
|
||||
let legacy_landlock_sandbox = legacy_landlock_json.get("sandbox").and_then(Value::as_str);
|
||||
|
||||
let expected_with_bubblewrap =
|
||||
sandbox_tag(&sandbox_policy, WindowsSandboxLevel::Disabled, true);
|
||||
assert_eq!(with_bubblewrap_sandbox, Some(expected_with_bubblewrap));
|
||||
let expected_default_bubblewrap =
|
||||
sandbox_tag(&sandbox_policy, WindowsSandboxLevel::Disabled, false);
|
||||
assert_eq!(
|
||||
default_bubblewrap_sandbox,
|
||||
Some(expected_default_bubblewrap)
|
||||
);
|
||||
|
||||
if cfg!(target_os = "linux") {
|
||||
assert_eq!(with_bubblewrap_sandbox, Some("linux_bubblewrap"));
|
||||
assert_ne!(with_bubblewrap_sandbox, without_bubblewrap_sandbox);
|
||||
assert_eq!(default_bubblewrap_sandbox, Some("linux_bubblewrap"));
|
||||
assert_ne!(default_bubblewrap_sandbox, legacy_landlock_sandbox);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user