Require the elevated Windows sandbox for network proxies (#32857)

## Why

Network proxy enforcement on Windows requires the elevated sandbox backend. Silently selecting that backend for an unelevated configuration makes the effective sandbox differ from the configured mode.

## What changed

- Reject enabled network proxy configurations on Windows unless managed requirements allow only the elevated sandbox and `windows.sandbox` resolves to `"elevated"`.
- Preserve the configured sandbox backend during execution and validate proxy compatibility at config loading, sandbox setup, and process launch boundaries.
- Defer this validation during cloud-config bootstrap so authoritative managed requirements can be loaded first.
- Do not start or expose disabled Windows proxies, and render transitions to disabled networking as `<network enabled="false"></network>`.

## Testing

- Cover Windows requirement and sandbox compatibility matrices, bootstrap behavior, backend selection, disabled proxy handling, and environment-context updates.

GitOrigin-RevId: bfa1dda98594e0db61883f8e7f65bd560e3453e6
This commit is contained in:
iceweasel-oai authored and copyberry committed 2026-07-13 19:04:22 +00:00
1 parent 87f3e39fdf
commit abbb8c569c
23 files changed
+496 -58

No files matched your search

+109 -6
View File
@@ -601,6 +601,56 @@ fn build_network_proxy_spec(
})
}
pub fn validate_windows_sandbox_network_proxy_compatibility(
windows_sandbox_level: WindowsSandboxLevel,
network_proxy_configured: bool,
) -> std::io::Result<()> {
validate_windows_sandbox_network_proxy_compatibility_for_platform(
cfg!(target_os = "windows"),
windows_sandbox_level,
network_proxy_configured,
)
}
fn validate_windows_sandbox_network_proxy_compatibility_for_platform(
is_windows: bool,
windows_sandbox_level: WindowsSandboxLevel,
network_proxy_configured: bool,
) -> std::io::Result<()> {
if is_windows
&& network_proxy_configured
&& windows_sandbox_level != WindowsSandboxLevel::Elevated
{
return Err(ConstraintError::NetworkProxyIncompatibleWithUnelevatedWindowsSandbox.into());
}
Ok(())
}
fn validate_windows_network_proxy_requirements(
requirements: &ConfigRequirementsToml,
network_proxy_configured: bool,
) -> std::io::Result<()> {
validate_windows_network_proxy_requirements_for_platform(
cfg!(target_os = "windows"),
requirements,
network_proxy_configured,
)
}
fn validate_windows_network_proxy_requirements_for_platform(
is_windows: bool,
requirements: &ConfigRequirementsToml,
network_proxy_configured: bool,
) -> std::io::Result<()> {
if is_windows
&& network_proxy_configured
&& !requirements.allows_only_elevated_windows_sandbox()
{
return Err(ConstraintError::NetworkProxyRequiresElevatedWindowsSandboxRequirement.into());
}
Ok(())
}
/// Configured thread persistence backend.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum ThreadStoreConfig {
@@ -1230,6 +1280,12 @@ impl AuthManagerConfig for Config {
}
}
#[derive(Clone, Copy)]
enum ConfigBuildPhase {
CloudConfigBootstrap,
Authoritative,
}
#[derive(Clone, Default)]
pub struct ConfigBuilder {
codex_home: Option<PathBuf>,
@@ -1288,10 +1344,15 @@ impl ConfigBuilder {
pub async fn build(self) -> std::io::Result<Config> {
// Keep the large config-loading future off small runtime thread stacks.
Box::pin(self.build_inner()).await
Box::pin(self.build_inner(ConfigBuildPhase::Authoritative)).await
}
async fn build_inner(self) -> std::io::Result<Config> {
/// Builds the preliminary config needed to initialize cloud config loading.
pub async fn build_for_cloud_config_bootstrap(self) -> std::io::Result<Config> {
Box::pin(self.build_inner(ConfigBuildPhase::CloudConfigBootstrap)).await
}
async fn build_inner(self, build_phase: ConfigBuildPhase) -> std::io::Result<Config> {
let Self {
codex_home,
cli_overrides,
@@ -1376,12 +1437,13 @@ impl ConfigBuilder {
config_layer_stack.requirements().clone(),
config_layer_stack.requirements_toml().clone(),
)?;
let mut config = Config::load_config_with_layer_stack(
let mut config = Config::load_config_with_layer_stack_and_options(
LOCAL_FS.as_ref(),
lock_config_toml,
harness_overrides,
codex_home,
lock_config_layer_stack,
build_phase,
)
.await?;
config.config_lock_toml = Some(Arc::new(expected_lock_config));
@@ -1390,12 +1452,13 @@ impl ConfigBuilder {
save_fields_resolved_from_model_catalog;
return Ok(config);
}
Config::load_config_with_layer_stack(
Config::load_config_with_layer_stack_and_options(
LOCAL_FS.as_ref(),
config_toml,
harness_overrides,
codex_home,
config_layer_stack,
build_phase,
)
.await
}
@@ -2967,6 +3030,25 @@ impl Config {
overrides: ConfigOverrides,
codex_home: AbsolutePathBuf,
config_layer_stack: ConfigLayerStack,
) -> std::io::Result<Self> {
Self::load_config_with_layer_stack_and_options(
fs,
cfg,
overrides,
codex_home,
config_layer_stack,
ConfigBuildPhase::Authoritative,
)
.await
}
async fn load_config_with_layer_stack_and_options(
fs: &dyn ExecutorFileSystem,
cfg: ConfigToml,
overrides: ConfigOverrides,
codex_home: AbsolutePathBuf,
config_layer_stack: ConfigLayerStack,
build_phase: ConfigBuildPhase,
) -> std::io::Result<Self> {
// Keep the large config-construction future off small test thread stacks.
Box::pin(async move {
@@ -3764,6 +3846,17 @@ impl Config {
network_requirements,
&network_permission_profile,
)?;
if matches!(build_phase, ConfigBuildPhase::Authoritative) {
let network_proxy_enabled = network.as_ref().is_some_and(NetworkProxySpec::enabled);
validate_windows_network_proxy_requirements(
config_layer_stack.requirements_toml(),
network_proxy_enabled,
)?;
validate_windows_sandbox_network_proxy_compatibility(
windows_sandbox_level,
network_proxy_enabled,
)?;
}
let mut helper_readable_roots = get_readable_roots_required_for_codex_runtime(
&codex_home,
zsh_path.as_ref(),
@@ -4157,11 +4250,21 @@ impl Config {
NetworkProxyConfig::default()
};
build_network_proxy_spec(
let network = build_network_proxy_spec(
configured_network_proxy_config,
self.config_layer_stack.requirements().network.clone(),
permission_profile,
)
)?;
let network_proxy_enabled = network.as_ref().is_some_and(NetworkProxySpec::enabled);
validate_windows_network_proxy_requirements(
self.config_layer_stack.requirements_toml(),
network_proxy_enabled,
)?;
validate_windows_sandbox_network_proxy_compatibility(
WindowsSandboxLevel::from_config(self),
network_proxy_enabled,
)?;
Ok(network)
}
pub fn bundled_skills_enabled(&self) -> bool {