mirror of
https://github.com/openai/codex.git
synced 2026-09-06 15:29:32 +00:00
Add a native Windows MXC sandbox adapter (#42841)
## What changed - Add `codex-mxc-sandbox` with native MXC availability detection and a launcher that inherits standard I/O and waits for the sandboxed process. - Reject unsupported learning-mode and fallback policies, and verify deny-path support before launch. - Route the existing Windows MXC availability metric through the new crate and move its Windows linking dependencies alongside the adapter. GitOrigin-RevId: e2a220b85718e00b0e710c30bbe66b6c56958176
This commit is contained in:
15
codex-rs/Cargo.lock
generated
15
codex-rs/Cargo.lock
generated
@@ -3992,6 +3992,18 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-mxc-sandbox"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"appcontainer_common",
|
||||
"codex-protocol",
|
||||
"learning_mode_windows",
|
||||
"tracelogging",
|
||||
"wxc_common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-network-proxy"
|
||||
version = "0.0.0"
|
||||
@@ -4331,7 +4343,7 @@ name = "codex-sandboxing"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"appcontainer_common",
|
||||
"codex-mxc-sandbox",
|
||||
"codex-network-proxy",
|
||||
"codex-otel",
|
||||
"codex-protocol",
|
||||
@@ -4347,7 +4359,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tracelogging",
|
||||
"tracing",
|
||||
"url",
|
||||
"which 8.0.0",
|
||||
|
||||
@@ -83,6 +83,7 @@ members = [
|
||||
"memories/read",
|
||||
"memories/write",
|
||||
"model-provider-info",
|
||||
"mxc-sandbox",
|
||||
"models-manager",
|
||||
"network-proxy",
|
||||
"ollama",
|
||||
@@ -240,6 +241,7 @@ codex-mcp-extension = { path = "ext/mcp" }
|
||||
codex-mcp-server = { path = "mcp-server" }
|
||||
codex-model-provider-info = { path = "model-provider-info" }
|
||||
codex-models-manager = { path = "models-manager" }
|
||||
codex-mxc-sandbox = { path = "mxc-sandbox" }
|
||||
codex-network-proxy = { path = "network-proxy" }
|
||||
codex-ollama = { path = "ollama" }
|
||||
codex-otel = { path = "otel" }
|
||||
@@ -302,6 +304,8 @@ core_test_support = { path = "core/tests/common" }
|
||||
mcp_test_support = { path = "mcp-server/tests/common" }
|
||||
|
||||
# External
|
||||
learning_mode_windows = { git = "https://github.com/microsoft/mxc", rev = "6cd3d58f05d3447e67109cfb75e042803b843ca4" }
|
||||
wxc_common = { git = "https://github.com/microsoft/mxc", rev = "6cd3d58f05d3447e67109cfb75e042803b843ca4" }
|
||||
age = "0.11.1"
|
||||
ansi-to-tui = "8.0.1"
|
||||
anyhow = "1"
|
||||
|
||||
6
codex-rs/mxc-sandbox/BUILD.bazel
Normal file
6
codex-rs/mxc-sandbox/BUILD.bazel
Normal file
@@ -0,0 +1,6 @@
|
||||
load("//:defs.bzl", "codex_rust_crate")
|
||||
|
||||
codex_rust_crate(
|
||||
name = "mxc-sandbox",
|
||||
crate_name = "codex_mxc_sandbox",
|
||||
)
|
||||
29
codex-rs/mxc-sandbox/Cargo.toml
Normal file
29
codex-rs/mxc-sandbox/Cargo.toml
Normal file
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "codex-mxc-sandbox"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[lib]
|
||||
test = false
|
||||
doctest = false
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
# This direct dependency pins MXC's transitive ETW dependency for Windows GNU linking.
|
||||
[package.metadata.cargo-shear]
|
||||
ignored = ["tracelogging"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
wxc_common = { workspace = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
appcontainer_common = { workspace = true }
|
||||
learning_mode_windows = { workspace = true }
|
||||
# 1.2.4 imports OneCore_apiset, which the GNU Windows toolchain does not ship.
|
||||
tracelogging = "=1.2.3"
|
||||
|
||||
[dev-dependencies]
|
||||
27
codex-rs/mxc-sandbox/src/lib.rs
Normal file
27
codex-rs/mxc-sandbox/src/lib.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
//! Native Windows process security environment availability and launch.
|
||||
|
||||
#[cfg(windows)]
|
||||
pub mod native;
|
||||
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Typed inputs for the native policy adapter.
|
||||
pub struct MxcCommand {
|
||||
pub permissions: PermissionProfile,
|
||||
pub sandbox_policy_cwd: PathBuf,
|
||||
pub command: Vec<String>,
|
||||
}
|
||||
|
||||
/// Whether the executor can create a native MXC process security environment.
|
||||
/// This deliberately excludes MXC's older AppContainer fallback backends.
|
||||
pub fn is_available() -> bool {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
appcontainer_common::base_container_runner::BaseContainerRunner::is_process_security_environment_usable()
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
false
|
||||
}
|
||||
}
|
||||
55
codex-rs/mxc-sandbox/src/native.rs
Normal file
55
codex-rs/mxc-sandbox/src/native.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
//! Run an already prepared MXC request with inherited stdio and job ownership.
|
||||
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use anyhow::ensure;
|
||||
use appcontainer_common::base_container_runner::BaseContainerRunner;
|
||||
use learning_mode_windows::SecurityEnvironmentApi;
|
||||
use wxc_common::logger::Logger;
|
||||
use wxc_common::logger::Mode;
|
||||
use wxc_common::models::ExecutionRequest;
|
||||
use wxc_common::sandbox_process::SandboxBackend;
|
||||
use wxc_common::sandbox_process::StdioMode;
|
||||
|
||||
// The ETW functions used by tracelogging are documented Advapi32 exports on
|
||||
// both Windows toolchains; 1.2.3 leaves their import library to the application.
|
||||
#[link(name = "advapi32")]
|
||||
unsafe extern "system" {}
|
||||
|
||||
/// Launch a native-only request and wait for its exit status.
|
||||
pub fn launch(request: &ExecutionRequest) -> Result<i32> {
|
||||
ensure!(
|
||||
!request
|
||||
.policy
|
||||
.capabilities
|
||||
.iter()
|
||||
.any(|capability| capability.eq_ignore_ascii_case("permissiveLearningMode")),
|
||||
"MXC native launch does not support permissiveLearningMode"
|
||||
);
|
||||
ensure!(
|
||||
crate::is_available(),
|
||||
"native MXC is unavailable on this Windows build"
|
||||
);
|
||||
ensure!(
|
||||
!request.policy.least_privilege_mode
|
||||
&& !request.policy.network_proxy.is_enabled()
|
||||
&& request.policy.capture_denials.is_none()
|
||||
&& !request.policy.fallback.allow_dacl_mutation,
|
||||
"MXC native launch does not support fallback policies"
|
||||
);
|
||||
// With no least-privilege mode, legacy proxy, or capture enabled, this
|
||||
// probe guarantees BaseContainerRunner chooses PSEC rather than SBOX.
|
||||
if !request.policy.denied_paths.is_empty() {
|
||||
ensure!(
|
||||
SecurityEnvironmentApi::load()?.supports_deny_paths()?,
|
||||
"this Windows build cannot enforce native MXC deny paths"
|
||||
);
|
||||
}
|
||||
let mut logger = Logger::new(Mode::Buffer);
|
||||
let mut child = BaseContainerRunner::new()
|
||||
.spawn(request, &mut logger, StdioMode::Inherit)
|
||||
.map_err(|error| anyhow::anyhow!("{}", error.error_message))?;
|
||||
// Do not publish the SDK diagnostic buffer: it may contain command or
|
||||
// environment data. This wrapper emits only the resulting launch error.
|
||||
child.wait().context("waiting for the MXC command")
|
||||
}
|
||||
@@ -12,10 +12,6 @@ doctest = false
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
# This direct dependency pins MXC's transitive ETW dependency for Windows GNU linking.
|
||||
[package.metadata.cargo-shear]
|
||||
ignored = ["tracelogging"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
codex-network-proxy = { workspace = true }
|
||||
@@ -34,11 +30,9 @@ url = { workspace = true }
|
||||
which = { workspace = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
appcontainer_common = { workspace = true }
|
||||
codex-mxc-sandbox = { workspace = true }
|
||||
codex-otel = { workspace = true }
|
||||
codex-utils-home-dir = { workspace = true }
|
||||
# 1.2.4 imports OneCore_apiset, which the GNU Windows toolchain does not ship.
|
||||
tracelogging = "=1.2.3"
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = { workspace = true }
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
//! Native Windows MXC capability discovery and availability metrics.
|
||||
//! Probing is cached upstream; reporting happens at most once per process.
|
||||
|
||||
use appcontainer_common::base_container_runner::BaseContainerRunner;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
static AVAILABILITY_RECORDED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
// tracelogging 1.2.3 leaves its ETW import library to the application. These
|
||||
// APIs are exported by Advapi32 in both the MSVC and GNU Windows toolchains.
|
||||
#[link(name = "advapi32")]
|
||||
unsafe extern "system" {}
|
||||
|
||||
pub(super) fn record_availability_once() {
|
||||
// Probe actual PSEC create/close support; symbol presence alone also
|
||||
// succeeds on transitional Windows builds where MXC is not enabled.
|
||||
let available = BaseContainerRunner::is_process_security_environment_usable();
|
||||
let available = codex_mxc_sandbox::is_available();
|
||||
if let Some(metrics) = codex_otel::global()
|
||||
&& !AVAILABILITY_RECORDED.swap(true, Ordering::Relaxed)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user