linux-sandbox: switch helper plumbing to PermissionProfile (#20106)

## Why

`PermissionProfile` is the canonical runtime permission model in the
Rust workspace, but the Linux sandbox helper still accepted a legacy
`SandboxPolicy` plus separate filesystem and network policy flags. That
translation layer made the helper interface harder to reason about and
left `linux-sandbox`-specific callers and tests coupled to the legacy
policy representation.

This change moves the helper onto `PermissionProfile` directly so the
Linux sandbox plumbing matches the rest of the permission stack.

## What changed

- changed `codex-linux-sandbox` to accept `--permission-profile` and
derive the runtime filesystem and network policies internally
- updated the in-process seccomp and legacy Landlock path in
`codex-rs/linux-sandbox` to operate on `PermissionProfile`
- updated Linux sandbox argv construction in `codex-rs/sandboxing`,
`codex-rs/core`, and the CLI debug sandbox path to pass the canonical
profile instead of serializing compatibility policy projections
- simplified the Linux sandbox tests to build the exact permission
profile under test, including the managed-proxy path and
direct-runtime-enforcement carveout coverage
- removed helper-local `SandboxPolicy` usage from `bwrap` tests where
`FileSystemSandboxPolicy` is already the value being exercised

## Testing

- `cargo test -p codex-sandboxing`
- `cargo test -p codex-linux-sandbox` (on this macOS host, the crate
compiled cleanly and its Linux-only tests were cfg-gated)
- `cargo test -p codex-core --no-run`
- `cargo test -p codex-cli --no-run`
This commit is contained in:
Michael Bolin
2026-04-28 19:43:44 -07:00
committed by GitHub
parent 80fb0704ee
commit e6db1a9442
11 changed files with 201 additions and 518 deletions
+6 -17
View File
@@ -3,10 +3,9 @@ use crate::spawn::StdioPolicy;
use crate::spawn::spawn_child_async;
use codex_network_proxy::NetworkProxy;
use codex_protocol::models::PermissionProfile;
use codex_sandboxing::compatibility_sandbox_policy_for_permission_profile;
use codex_sandboxing::landlock::CODEX_LINUX_SANDBOX_ARG0;
use codex_sandboxing::landlock::allow_network_for_proxy;
use codex_sandboxing::landlock::create_linux_sandbox_command_args_for_policies;
use codex_sandboxing::landlock::create_linux_sandbox_command_args_for_permission_profile;
use codex_utils_absolute_path::AbsolutePathBuf;
use std::collections::HashMap;
use std::path::Path;
@@ -17,9 +16,8 @@ use tokio::process::Child;
/// isolation plus seccomp for network restrictions.
///
/// Unlike macOS Seatbelt where we directly embed the policy text, the Linux
/// helper is a separate executable. We pass both the canonical split
/// filesystem/network policies and a compatibility legacy projection as JSON
/// until the helper protocol no longer needs the legacy field.
/// helper is a separate executable. We pass the canonical permission profile
/// as JSON and let the helper derive the runtime filesystem/network policies.
#[allow(clippy::too_many_arguments)]
pub async fn spawn_command_under_linux_sandbox<P>(
codex_linux_sandbox_exe: P,
@@ -35,20 +33,11 @@ pub async fn spawn_command_under_linux_sandbox<P>(
where
P: AsRef<Path>,
{
let (file_system_sandbox_policy, network_sandbox_policy) =
permission_profile.to_runtime_permissions();
let sandbox_policy = compatibility_sandbox_policy_for_permission_profile(
permission_profile,
&file_system_sandbox_policy,
network_sandbox_policy,
sandbox_policy_cwd.as_path(),
);
let args = create_linux_sandbox_command_args_for_policies(
let network_sandbox_policy = permission_profile.network_sandbox_policy();
let args = create_linux_sandbox_command_args_for_permission_profile(
command,
command_cwd.as_path(),
&sandbox_policy,
&file_system_sandbox_policy,
network_sandbox_policy,
permission_profile,
sandbox_policy_cwd,
use_legacy_landlock,
allow_network_for_proxy(/*enforce_managed_network*/ false),