Add network environment ID plumbing (#28766)

## Why

Prepare network approval scoping to distinguish execution environments
without changing behavior yet.

## What changed

- Add optional environment IDs to network policy requests.
- Add optional network environment IDs to exec and sandbox request
structs.
- Thread default None values through existing construction points.
- Fix stale constructor call sites that caused the CI compile failures.

## Not included

- Per-environment proxy listeners.
- Network approval cache or prompt behavior changes.
- Ambiguous request attribution handling.

Those behavior changes moved to stacked follow-up #28899.

## Validation

- just fmt
- CI will run tests and clippy
This commit is contained in:
jif
2026-06-18 13:09:38 +01:00
committed by GitHub
Unverified
parent ecc4c30e28
commit 0369b24d54
21 changed files with 60 additions and 0 deletions
+3
View File
@@ -704,6 +704,7 @@ mod tests {
cwd.clone(),
HashMap::new(),
/*network*/ None,
/*network_environment_id*/ None,
ExecExpiration::DefaultTimeout,
codex_core::exec::ExecCapturePolicy::ShellTool,
SandboxType::WindowsRestrictedToken,
@@ -821,6 +822,7 @@ mod tests {
cwd.clone(),
HashMap::new(),
/*network*/ None,
/*network_environment_id*/ None,
ExecExpiration::Cancellation(CancellationToken::new()),
codex_core::exec::ExecCapturePolicy::ShellTool,
SandboxType::None,
@@ -908,6 +910,7 @@ mod tests {
cwd.clone(),
HashMap::new(),
/*network*/ None,
/*network_environment_id*/ None,
ExecExpiration::TimeoutOrCancellation {
timeout: Duration::from_secs(30),
cancellation,
@@ -297,6 +297,7 @@ impl CommandExecRequestProcessor {
network: started_network_proxy
.as_ref()
.map(codex_core::config::StartedNetworkProxy::proxy),
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level,
windows_sandbox_private_desktop: self
+7
View File
@@ -95,6 +95,7 @@ pub struct ExecParams {
pub capture_policy: ExecCapturePolicy,
pub env: HashMap<String, String>,
pub network: Option<NetworkProxy>,
pub network_environment_id: Option<String>,
pub sandbox_permissions: SandboxPermissions,
pub windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel,
pub windows_sandbox_private_desktop: bool,
@@ -321,6 +322,7 @@ pub fn build_exec_request(
expiration,
capture_policy,
network,
network_environment_id,
windows_sandbox_level,
windows_sandbox_private_desktop,
@@ -372,6 +374,7 @@ pub fn build_exec_request(
permissions: permission_profile,
sandbox: sandbox_type,
enforce_managed_network,
environment_id: network_environment_id.as_deref(),
network: network.as_ref(),
sandbox_policy_cwd: &sandbox_policy_cwd_uri,
codex_linux_sandbox_exe: codex_linux_sandbox_exe.as_deref(),
@@ -437,6 +440,7 @@ pub(crate) async fn execute_exec_request(
file_system_sandbox_policy: _,
network_sandbox_policy,
windows_sandbox_filesystem_overrides,
network_environment_id,
arg0,
} = exec_request;
@@ -456,6 +460,7 @@ pub(crate) async fn execute_exec_request(
capture_policy,
env,
network: network.clone(),
network_environment_id,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level,
windows_sandbox_private_desktop,
@@ -593,6 +598,7 @@ async fn exec_windows_sandbox(
cwd,
mut env,
network,
network_environment_id: _,
expiration,
capture_policy,
windows_sandbox_level,
@@ -941,6 +947,7 @@ async fn exec(
cwd,
mut env,
network,
network_environment_id: _,
arg0,
expiration,
capture_policy,
+7
View File
@@ -273,6 +273,7 @@ async fn exec_full_buffer_capture_ignores_expiration() -> Result<()> {
capture_policy: ExecCapturePolicy::FullBuffer,
env,
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
@@ -309,6 +310,7 @@ async fn exec_full_buffer_capture_keeps_io_drain_timeout_when_descendant_holds_p
capture_policy: ExecCapturePolicy::FullBuffer,
env: std::env::vars().collect(),
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
@@ -356,6 +358,7 @@ async fn process_exec_tool_call_preserves_full_buffer_capture_policy() -> Result
capture_policy: ExecCapturePolicy::FullBuffer,
env: std::env::vars().collect(),
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
@@ -998,6 +1001,7 @@ fn build_exec_request_preserves_windows_workspace_roots() -> Result<()> {
capture_policy: ExecCapturePolicy::ShellTool,
env: HashMap::new(),
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
@@ -1052,6 +1056,7 @@ async fn kill_child_process_group_kills_grandchildren_on_timeout() -> Result<()>
capture_policy: ExecCapturePolicy::ShellTool,
env,
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
@@ -1107,6 +1112,7 @@ async fn process_exec_tool_call_respects_cancellation_token() -> Result<()> {
capture_policy: ExecCapturePolicy::ShellTool,
env,
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
@@ -1190,6 +1196,7 @@ while :; do sleep 1; done"#
capture_policy: ExecCapturePolicy::ShellTool,
env,
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
+5
View File
@@ -47,6 +47,7 @@ pub struct ExecRequest {
pub env: HashMap<String, String>,
pub(crate) exec_server_env_config: Option<ExecServerEnvConfig>,
pub network: Option<NetworkProxy>,
pub network_environment_id: Option<String>,
pub expiration: ExecExpiration,
pub capture_policy: ExecCapturePolicy,
pub sandbox: SandboxType,
@@ -68,6 +69,7 @@ impl ExecRequest {
cwd: AbsolutePathBuf,
env: HashMap<String, String>,
network: Option<NetworkProxy>,
network_environment_id: Option<String>,
expiration: ExecExpiration,
capture_policy: ExecCapturePolicy,
sandbox: SandboxType,
@@ -87,6 +89,7 @@ impl ExecRequest {
env,
exec_server_env_config: None,
network,
network_environment_id,
expiration,
capture_policy,
sandbox,
@@ -113,6 +116,7 @@ impl ExecRequest {
sandbox_policy_cwd: windows_sandbox_policy_cwd,
mut env,
network,
network_environment_id,
sandbox,
windows_sandbox_level,
windows_sandbox_private_desktop,
@@ -141,6 +145,7 @@ impl ExecRequest {
env,
exec_server_env_config: None,
network,
network_environment_id,
expiration,
capture_policy,
sandbox,
+1
View File
@@ -205,6 +205,7 @@ pub(crate) async fn execute_user_shell_command(
// `/shell` is the explicit full-access escape hatch, so it must not
// inherit a managed proxy from the surrounding session or turn.
network: None,
network_environment_id: None,
// TODO(zhao-oai): Now that we have ExecExpiration::Cancellation, we
// should use that instead of an "arbitrarily large" timeout here.
expiration: USER_SHELL_TIMEOUT_MS.into(),
@@ -105,6 +105,7 @@ impl ShellCommandHandler {
Some(thread_id),
),
network: turn_context.network.clone(),
network_environment_id: None,
sandbox_permissions: params.sandbox_permissions.unwrap_or_default(),
windows_sandbox_level: turn_context.windows_sandbox_level,
windows_sandbox_private_desktop: turn_context
@@ -151,6 +151,7 @@ pub(super) async fn try_run_zsh_fork(
env: sandbox_env,
exec_server_env_config: _,
network: sandbox_network,
network_environment_id: _,
expiration: _sandbox_expiration,
capture_policy: _capture_policy,
sandbox,
@@ -879,6 +880,7 @@ impl CoreShellCommandExecutor {
env: exec_env,
exec_server_env_config: None,
network: self.network.clone(),
network_environment_id: None,
expiration: ExecExpiration::Cancellation(cancel_rx),
capture_policy: ExecCapturePolicy::ShellTool,
sandbox: self.sandbox,
@@ -1010,6 +1012,7 @@ impl CoreShellCommandExecutor {
permissions: permission_profile,
sandbox,
enforce_managed_network: self.network.is_some(),
environment_id: None,
network: self.network.as_ref(),
sandbox_policy_cwd: &sandbox_policy_cwd,
codex_linux_sandbox_exe: self.codex_linux_sandbox_exe.as_deref(),
+1
View File
@@ -434,6 +434,7 @@ impl<'a> SandboxAttempt<'a> {
permissions: self.permissions,
sandbox: self.sandbox,
enforce_managed_network: self.enforce_managed_network,
environment_id: None,
network,
sandbox_policy_cwd: self.sandbox_cwd,
codex_linux_sandbox_exe: self
@@ -77,6 +77,7 @@ fn test_exec_request(
cwd,
env,
network,
/*network_environment_id*/ None,
ExecExpiration::DefaultTimeout,
ExecCapturePolicy::ShellTool,
SandboxType::None,
@@ -98,6 +98,7 @@ fn exec_server_params_use_path_uri_and_env_policy_overlay_contract() {
]),
}),
network: None,
network_environment_id: None,
expiration: crate::exec::ExecExpiration::DefaultTimeout,
capture_policy: crate::exec::ExecCapturePolicy::ShellTool,
sandbox: codex_sandboxing::SandboxType::None,
+1
View File
@@ -41,6 +41,7 @@ where
capture_policy: ExecCapturePolicy::ShellTool,
env: HashMap::new(),
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
@@ -173,6 +173,7 @@ async fn windows_restricted_token_rejects_exact_and_glob_deny_read_policy() -> a
capture_policy: ExecCapturePolicy::ShellTool,
env: HashMap::new(),
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: WindowsSandboxLevel::RestrictedToken,
windows_sandbox_private_desktop: false,
@@ -262,6 +263,7 @@ async fn windows_elevated_enforces_deny_read_and_protects_setup_marker() -> anyh
capture_policy: ExecCapturePolicy::ShellTool,
env: HashMap::new(),
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: WindowsSandboxLevel::Elevated,
windows_sandbox_private_desktop: false,
+1
View File
@@ -135,6 +135,7 @@ impl FileSystemSandboxRunner {
permissions: permission_profile,
sandbox,
enforce_managed_network: false,
environment_id: None,
network: None,
sandbox_policy_cwd: &cwd.uri,
codex_linux_sandbox_exe: self.runtime_paths.codex_linux_sandbox_exe.as_deref(),
+1
View File
@@ -36,6 +36,7 @@ async fn spawn_command_under_sandbox(
capture_policy: ExecCapturePolicy::ShellTool,
env,
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
@@ -175,6 +175,7 @@ async fn run_cmd_result_with_permission_profile_for_cwd(
capture_policy: ExecCapturePolicy::ShellTool,
env: create_env_from_core_vars(),
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
@@ -432,6 +433,7 @@ async fn assert_network_blocked(cmd: &[&str]) {
capture_policy: ExecCapturePolicy::ShellTool,
env: create_env_from_core_vars(),
network: None,
network_environment_id: None,
sandbox_permissions: SandboxPermissions::UseDefault,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
+2
View File
@@ -200,6 +200,7 @@ async fn http_connect_accept(
protocol: NetworkProtocol::HttpsConnect,
host: host.clone(),
port: authority.port,
environment_id: None,
client_addr: client.clone(),
method: Some("CONNECT".to_string()),
command: None,
@@ -683,6 +684,7 @@ async fn http_plain_proxy(
protocol: NetworkProtocol::Http,
host: host.clone(),
port,
environment_id: None,
client_addr: client.clone(),
method: Some(req.method().as_str().to_string()),
command: None,
@@ -79,6 +79,7 @@ pub struct NetworkPolicyRequest {
pub protocol: NetworkProtocol,
pub host: String,
pub port: u16,
pub environment_id: Option<String>,
pub client_addr: Option<String>,
pub method: Option<String>,
pub command: Option<String>,
@@ -89,6 +90,7 @@ pub struct NetworkPolicyRequestArgs {
pub protocol: NetworkProtocol,
pub host: String,
pub port: u16,
pub environment_id: Option<String>,
pub client_addr: Option<String>,
pub method: Option<String>,
pub command: Option<String>,
@@ -101,6 +103,7 @@ impl NetworkPolicyRequest {
protocol,
host,
port,
environment_id,
client_addr,
method,
command,
@@ -110,6 +113,7 @@ impl NetworkPolicyRequest {
protocol,
host,
port,
environment_id,
client_addr,
method,
command,
@@ -625,6 +629,7 @@ mod tests {
protocol: NetworkProtocol::Http,
host: "example.com".to_string(),
port: 80,
environment_id: None,
client_addr: None,
method: None,
command: None,
@@ -686,6 +691,7 @@ mod tests {
protocol: NetworkProtocol::Http,
host: "blocked.com".to_string(),
port: 80,
environment_id: None,
client_addr: Some("127.0.0.1:1234".to_string()),
method: Some("GET".to_string()),
command: None,
@@ -729,6 +735,7 @@ mod tests {
protocol: NetworkProtocol::Http,
host: "example.com".to_string(),
port: 80,
environment_id: None,
client_addr: None,
method: Some("GET".to_string()),
command: None,
@@ -779,6 +786,7 @@ mod tests {
protocol: NetworkProtocol::Http,
host: "example.com".to_string(),
port: 80,
environment_id: None,
client_addr: None,
method: Some("GET".to_string()),
command: None,
@@ -865,6 +873,7 @@ mod tests {
protocol: NetworkProtocol::Http,
host: "127.0.0.1".to_string(),
port: 80,
environment_id: None,
client_addr: None,
method: Some("GET".to_string()),
command: None,
+2
View File
@@ -268,6 +268,7 @@ async fn handle_socks5_tcp(
protocol: NetworkProtocol::Socks5Tcp,
host: host.clone(),
port,
environment_id: None,
client_addr: client.clone(),
method: None,
command: None,
@@ -624,6 +625,7 @@ async fn inspect_socks5_udp(
protocol: NetworkProtocol::Socks5Udp,
host: host.clone(),
port,
environment_id: None,
client_addr: client.clone(),
method: None,
command: None,
+4
View File
@@ -113,6 +113,7 @@ pub struct SandboxExecRequest {
pub sandbox_policy_cwd: PathUri,
pub env: HashMap<String, String>,
pub network: Option<NetworkProxy>,
pub network_environment_id: Option<String>,
pub sandbox: SandboxType,
pub windows_sandbox_level: WindowsSandboxLevel,
pub windows_sandbox_private_desktop: bool,
@@ -130,6 +131,7 @@ pub struct SandboxTransformRequest<'a> {
pub permissions: &'a PermissionProfile,
pub sandbox: SandboxType,
pub enforce_managed_network: bool,
pub environment_id: Option<&'a str>,
// TODO(viyatb): Evaluate switching this to Option<Arc<NetworkProxy>>
// to make shared ownership explicit across runtime/sandbox plumbing.
pub network: Option<&'a NetworkProxy>,
@@ -305,6 +307,7 @@ impl SandboxManager {
permissions,
sandbox,
enforce_managed_network,
environment_id,
network,
sandbox_policy_cwd,
codex_linux_sandbox_exe,
@@ -422,6 +425,7 @@ impl SandboxManager {
sandbox_policy_cwd: sandbox_policy_cwd.clone(),
env: command.env,
network: network.cloned(),
network_environment_id: environment_id.map(str::to_string),
sandbox,
windows_sandbox_level,
windows_sandbox_private_desktop,
+5
View File
@@ -97,6 +97,7 @@ fn unsandboxed_transform_preserves_foreign_cwd_and_unrestricted_file_system_poli
permissions: &permissions,
sandbox: SandboxType::None,
enforce_managed_network: false,
environment_id: None,
network: None,
sandbox_policy_cwd: &cwd_uri,
codex_linux_sandbox_exe: None,
@@ -151,6 +152,7 @@ fn transform_additional_permissions_enable_network_for_external_sandbox() {
permissions: &permissions,
sandbox: SandboxType::None,
enforce_managed_network: false,
environment_id: None,
network: None,
sandbox_policy_cwd: &cwd_uri,
codex_linux_sandbox_exe: None,
@@ -220,6 +222,7 @@ fn transform_additional_permissions_preserves_denied_entries() {
permissions: &permissions,
sandbox: SandboxType::None,
enforce_managed_network: false,
environment_id: None,
network: None,
sandbox_policy_cwd: &cwd_uri,
codex_linux_sandbox_exe: None,
@@ -316,6 +319,7 @@ fn transform_linux_seccomp_request(
permissions: &permissions,
sandbox: SandboxType::LinuxSeccomp,
enforce_managed_network: false,
environment_id: None,
network: None,
sandbox_policy_cwd: &cwd_uri,
codex_linux_sandbox_exe: Some(codex_linux_sandbox_exe),
@@ -505,6 +509,7 @@ fn transform_for_direct_spawn_windows_materializes_inner_helper() {
permissions: &permissions,
sandbox: SandboxType::WindowsRestrictedToken,
enforce_managed_network: false,
environment_id: None,
network: None,
sandbox_policy_cwd: &cwd_uri,
codex_linux_sandbox_exe: None,