diff --git a/codex-rs/core/src/exec.rs b/codex-rs/core/src/exec.rs index ff00ca69e3..4aaf5cd067 100644 --- a/codex-rs/core/src/exec.rs +++ b/codex-rs/core/src/exec.rs @@ -665,6 +665,7 @@ async fn exec_windows_sandbox( elevated_read_roots_include_platform_defaults, write_roots_override: elevated_write_roots_override.as_deref(), deny_write_paths_override: &elevated_deny_write_paths, + protected_metadata_targets: &[], }, ) } else { diff --git a/codex-rs/windows-sandbox-rs/src/elevated_impl.rs b/codex-rs/windows-sandbox-rs/src/elevated_impl.rs index 2c1c4f79ce..d62be4dca8 100644 --- a/codex-rs/windows-sandbox-rs/src/elevated_impl.rs +++ b/codex-rs/windows-sandbox-rs/src/elevated_impl.rs @@ -2,6 +2,8 @@ use std::collections::HashMap; use std::path::Path; use std::path::PathBuf; +use crate::setup::ProtectedMetadataTarget; + pub struct ElevatedSandboxCaptureRequest<'a> { pub policy_json_or_preset: &'a str, pub sandbox_policy_cwd: &'a Path, @@ -16,6 +18,7 @@ pub struct ElevatedSandboxCaptureRequest<'a> { pub read_roots_include_platform_defaults: bool, pub write_roots_override: Option<&'a [PathBuf]>, pub deny_write_paths_override: &'a [PathBuf], + pub protected_metadata_targets: &'a [ProtectedMetadataTarget], } mod windows_impl { @@ -125,6 +128,7 @@ mod windows_impl { read_roots_include_platform_defaults, write_roots_override, deny_write_paths_override, + protected_metadata_targets, } = request; let policy = parse_policy(policy_json_or_preset)?; normalize_null_device_env(&mut env_map); @@ -147,6 +151,7 @@ mod windows_impl { read_roots_include_platform_defaults, write_roots_override, deny_write_paths_override, + protected_metadata_targets, proxy_enforced, )?; // Build capability SID for ACL grants. diff --git a/codex-rs/windows-sandbox-rs/src/identity.rs b/codex-rs/windows-sandbox-rs/src/identity.rs index 84e72341e2..93f5ab5e8b 100644 --- a/codex-rs/windows-sandbox-rs/src/identity.rs +++ b/codex-rs/windows-sandbox-rs/src/identity.rs @@ -140,6 +140,7 @@ pub fn require_logon_sandbox_creds( read_roots_include_platform_defaults: bool, write_roots_override: Option<&[PathBuf]>, deny_write_paths_override: &[PathBuf], + protected_metadata_targets: &[crate::setup::ProtectedMetadataTarget], proxy_enforced: bool, ) -> Result { let sandbox_dir = crate::setup::sandbox_dir(codex_home); @@ -202,6 +203,7 @@ pub fn require_logon_sandbox_creds( read_roots_include_platform_defaults, write_roots: Some(needed_write.clone()), deny_write_paths: Some(deny_write_paths_override.to_vec()), + protected_metadata_targets: Some(protected_metadata_targets.to_vec()), }, )?; identity = select_identity(network_identity, codex_home)?; @@ -221,6 +223,7 @@ pub fn require_logon_sandbox_creds( read_roots_include_platform_defaults, write_roots: Some(needed_write), deny_write_paths: Some(deny_write_paths_override.to_vec()), + protected_metadata_targets: Some(protected_metadata_targets.to_vec()), }, )?; let identity = identity.ok_or_else(|| { diff --git a/codex-rs/windows-sandbox-rs/src/setup_main_win.rs b/codex-rs/windows-sandbox-rs/src/setup_main_win.rs index ca3fc1e444..6e0f19ac4a 100644 --- a/codex-rs/windows-sandbox-rs/src/setup_main_win.rs +++ b/codex-rs/windows-sandbox-rs/src/setup_main_win.rs @@ -8,6 +8,7 @@ use base64::Engine; use base64::engine::general_purpose::STANDARD as BASE64; use codex_otel::StatsigMetricsSettings; use codex_windows_sandbox::LOG_FILE_NAME; +use codex_windows_sandbox::ProtectedMetadataTarget; use codex_windows_sandbox::SETUP_VERSION; use codex_windows_sandbox::SetupErrorCode; use codex_windows_sandbox::SetupErrorReport; @@ -87,6 +88,9 @@ struct Payload { write_roots: Vec, #[serde(default)] deny_write_paths: Vec, + #[allow(dead_code)] + #[serde(default)] + protected_metadata_targets: Vec, proxy_ports: Vec, #[serde(default)] allow_local_binding: bool, diff --git a/codex-rs/windows-sandbox-rs/src/setup_orchestrator.rs b/codex-rs/windows-sandbox-rs/src/setup_orchestrator.rs index 4ca80d12d3..0b7d821d23 100644 --- a/codex-rs/windows-sandbox-rs/src/setup_orchestrator.rs +++ b/codex-rs/windows-sandbox-rs/src/setup_orchestrator.rs @@ -97,6 +97,7 @@ pub struct SetupRootOverrides { pub read_roots_include_platform_defaults: bool, pub write_roots: Option>, pub deny_write_paths: Option>, + pub protected_metadata_targets: Option>, } /// Layer: Windows enforcement request boundary. These targets are projected by @@ -169,6 +170,7 @@ pub fn run_setup_refresh_with_extra_read_roots( read_roots_include_platform_defaults: false, write_roots: Some(Vec::new()), deny_write_paths: None, + protected_metadata_targets: None, }, ) } @@ -186,6 +188,8 @@ fn run_setup_refresh_inner( } let (read_roots, write_roots) = build_payload_roots(&request, &overrides); let deny_write_paths = build_payload_deny_write_paths(&request, overrides.deny_write_paths); + let protected_metadata_targets = + build_payload_protected_metadata_targets(overrides.protected_metadata_targets); let network_identity = SandboxNetworkIdentity::from_policy(request.policy, request.proxy_enforced); let offline_proxy_settings = offline_proxy_settings_from_env(request.env_map, network_identity); @@ -198,6 +202,7 @@ fn run_setup_refresh_inner( read_roots, write_roots, deny_write_paths, + protected_metadata_targets, proxy_ports: offline_proxy_settings.proxy_ports, allow_local_binding: offline_proxy_settings.allow_local_binding, otel: None, @@ -436,6 +441,8 @@ struct ElevationPayload { write_roots: Vec, #[serde(default)] deny_write_paths: Vec, + #[serde(default)] + protected_metadata_targets: Vec, proxy_ports: Vec, #[serde(default)] allow_local_binding: bool, @@ -738,6 +745,8 @@ pub fn run_elevated_setup( })?; let (read_roots, write_roots) = build_payload_roots(&request, &overrides); let deny_write_paths = build_payload_deny_write_paths(&request, overrides.deny_write_paths); + let protected_metadata_targets = + build_payload_protected_metadata_targets(overrides.protected_metadata_targets); let network_identity = SandboxNetworkIdentity::from_policy(request.policy, request.proxy_enforced); let offline_proxy_settings = offline_proxy_settings_from_env(request.env_map, network_identity); @@ -750,6 +759,7 @@ pub fn run_elevated_setup( read_roots, write_roots, deny_write_paths, + protected_metadata_targets, proxy_ports: offline_proxy_settings.proxy_ports, allow_local_binding: offline_proxy_settings.allow_local_binding, real_user: std::env::var("USERNAME").unwrap_or_else(|_| "Administrators".to_string()), @@ -834,6 +844,12 @@ fn build_payload_deny_write_paths( deny_write_paths } +fn build_payload_protected_metadata_targets( + explicit_targets: Option>, +) -> Vec { + explicit_targets.unwrap_or_default() +} + fn expand_user_profile_root(roots: Vec) -> Vec { let Ok(user_profile) = std::env::var("USERPROFILE") else { return roots; @@ -1345,6 +1361,7 @@ mod tests { read_roots_include_platform_defaults: true, write_roots: None, deny_write_paths: None, + protected_metadata_targets: None, }, ); let expected_helper = @@ -1392,6 +1409,7 @@ mod tests { read_roots_include_platform_defaults: false, write_roots: None, deny_write_paths: None, + protected_metadata_targets: None, }, ); let expected_helper = diff --git a/codex-rs/windows-sandbox-rs/src/spawn_prep.rs b/codex-rs/windows-sandbox-rs/src/spawn_prep.rs index 1b3704d6a2..022c219922 100644 --- a/codex-rs/windows-sandbox-rs/src/spawn_prep.rs +++ b/codex-rs/windows-sandbox-rs/src/spawn_prep.rs @@ -17,6 +17,7 @@ use crate::policy::SandboxPolicy; use crate::policy::parse_policy; use crate::sandbox_utils::ensure_codex_home_exists; use crate::sandbox_utils::inject_git_safe_directory; +use crate::setup::ProtectedMetadataTarget; use crate::token::convert_string_sid_to_sid; use crate::token::create_readonly_token_with_cap; use crate::token::create_workspace_write_token_with_caps_from; @@ -264,6 +265,7 @@ pub(crate) fn prepare_elevated_spawn_context( cwd: &Path, env_map: &mut HashMap, command: &[String], + protected_metadata_targets: &[ProtectedMetadataTarget], ) -> Result { let common = prepare_spawn_context_common( policy_json_or_preset, @@ -298,6 +300,7 @@ pub(crate) fn prepare_elevated_spawn_context( /*read_roots_include_platform_defaults*/ false, write_roots_override, &deny_write_paths, + protected_metadata_targets, /*proxy_enforced*/ false, )?; let caps = load_or_create_cap_sids(codex_home)?; diff --git a/codex-rs/windows-sandbox-rs/src/unified_exec/backends/elevated.rs b/codex-rs/windows-sandbox-rs/src/unified_exec/backends/elevated.rs index 4ee2b5fac5..ebd1326353 100644 --- a/codex-rs/windows-sandbox-rs/src/unified_exec/backends/elevated.rs +++ b/codex-rs/windows-sandbox-rs/src/unified_exec/backends/elevated.rs @@ -38,6 +38,7 @@ pub(crate) async fn spawn_windows_sandbox_session_elevated( cwd, &mut env_map, &command, + &[], )?; let spawn_request = SpawnRequest {