From c6b124bb31b5bc5db0142f3152e4a2ecd2dd2637 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 8 Jul 2026 13:22:10 -0700 Subject: [PATCH] [codex] Grant Windows sandbox access to primary runtime (#31574) ## Why Codex Desktop installs its managed primary runtime under `%USERPROFILE%\.cache\codex-runtimes`. Elevated Windows sandbox commands run as dedicated sandbox users. The synchronous runtime ACL refresh repairs read/execute access for the Desktop runtime directories under `%LOCALAPPDATA%\OpenAI\Codex`, but did not include the managed primary runtime cache. As a result, the Desktop app could discover a bundled runtime while a sandboxed command received `ACCESS_DENIED` when reading or executing it. ## What changed - Include `%USERPROFILE%\.cache\codex-runtimes` in the managed runtime paths considered by the Windows sandbox ACL refresh. - Reuse the existing inherited read/execute ACL repair; no write permission is added. - Add Windows-target regression coverage for the runtime path list and the primary-runtime-only case. ## Impact Bundled Python, Node, and native tools remain usable from elevated Windows sandbox sessions without broadening write access or granting access to the rest of the user profile. ## Validation - `just fmt` - `just test -p codex-windows-sandbox` (10/10 host-side tests passed) - Windows-target path tests included for CI --- .../bin/setup_main/win/setup_runtime_bin.rs | 30 ++++++++++++++----- .../setup_main/win/setup_runtime_bin_tests.rs | 28 +++++++++++++++++ 2 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 codex-rs/windows-sandbox-rs/src/bin/setup_main/win/setup_runtime_bin_tests.rs diff --git a/codex-rs/windows-sandbox-rs/src/bin/setup_main/win/setup_runtime_bin.rs b/codex-rs/windows-sandbox-rs/src/bin/setup_main/win/setup_runtime_bin.rs index 509670e36b..8b0498d756 100644 --- a/codex-rs/windows-sandbox-rs/src/bin/setup_main/win/setup_runtime_bin.rs +++ b/codex-rs/windows-sandbox-rs/src/bin/setup_main/win/setup_runtime_bin.rs @@ -10,20 +10,22 @@ use windows_sys::Win32::Security::OBJECT_INHERIT_ACE; use windows_sys::Win32::Storage::FileSystem::FILE_GENERIC_EXECUTE; use windows_sys::Win32::Storage::FileSystem::FILE_GENERIC_READ; +#[cfg(test)] +#[path = "setup_runtime_bin_tests.rs"] +mod tests; + pub(super) fn ensure_codex_app_runtime_paths_readable( sandbox_group_psid: *mut c_void, refresh_errors: &mut Vec, log: &mut dyn Write, ) -> Result<()> { - let local_app_data = local_app_data_root(); - let Some(local_app_data) = local_app_data else { - return Ok(()); - }; - let read_execute_mask = FILE_GENERIC_READ | FILE_GENERIC_EXECUTE; - let codex_root = local_app_data.join("OpenAI").join("Codex"); + let runtime_paths = runtime_paths( + local_app_data_root(), + std::env::var_os("USERPROFILE").map(PathBuf::from), + ); - for runtime_path in [codex_root.join("bin"), codex_root.join("runtimes")] { + for runtime_path in runtime_paths { if !runtime_path.is_dir() { continue; } @@ -86,6 +88,20 @@ pub(super) fn ensure_codex_app_runtime_paths_readable( Ok(()) } +fn runtime_paths(local_app_data: Option, user_profile: Option) -> Vec { + let mut runtime_paths = Vec::new(); + if let Some(local_app_data) = local_app_data { + let codex_root = local_app_data.join("OpenAI").join("Codex"); + runtime_paths.extend([codex_root.join("bin"), codex_root.join("runtimes")]); + } + // The managed primary runtime is installed outside the LocalAppData runtime roots. + if let Some(user_profile) = user_profile { + runtime_paths.push(user_profile.join(".cache").join("codex-runtimes")); + } + + runtime_paths +} + fn local_app_data_root() -> Option { std::env::var_os("LOCALAPPDATA") .map(PathBuf::from) diff --git a/codex-rs/windows-sandbox-rs/src/bin/setup_main/win/setup_runtime_bin_tests.rs b/codex-rs/windows-sandbox-rs/src/bin/setup_main/win/setup_runtime_bin_tests.rs new file mode 100644 index 0000000000..a3fa300d0b --- /dev/null +++ b/codex-rs/windows-sandbox-rs/src/bin/setup_main/win/setup_runtime_bin_tests.rs @@ -0,0 +1,28 @@ +use super::runtime_paths; +use pretty_assertions::assert_eq; +use std::path::PathBuf; + +#[test] +fn runtime_paths_include_desktop_and_primary_runtime_roots() { + let local_app_data = PathBuf::from(r"C:\Users\user\AppData\Local"); + let user_profile = PathBuf::from(r"C:\Users\user"); + + assert_eq!( + runtime_paths(Some(local_app_data), Some(user_profile)), + vec![ + PathBuf::from(r"C:\Users\user\AppData\Local\OpenAI\Codex\bin"), + PathBuf::from(r"C:\Users\user\AppData\Local\OpenAI\Codex\runtimes"), + PathBuf::from(r"C:\Users\user\.cache\codex-runtimes"), + ] + ); +} + +#[test] +fn primary_runtime_path_does_not_depend_on_local_app_data() { + let user_profile = PathBuf::from(r"C:\Users\user"); + + assert_eq!( + runtime_paths(/*local_app_data*/ None, Some(user_profile)), + vec![PathBuf::from(r"C:\Users\user\.cache\codex-runtimes")] + ); +}