From 8da8b0c7f75a627cfcba5229eba931c5af36240c Mon Sep 17 00:00:00 2001 From: Dmitriy Kovalenko Date: Tue, 3 Nov 2026 20:32:05 +0000 Subject: [PATCH] Fix test fixtures for Bazel sandboxes and Windows voice runtimes (#59231) ## What changed - Resolve Linux sandbox test binaries with `cargo_bin` and canonicalize the helper path used by the managed proxy filesystem policy so Bubblewrap can re-execute it. - Restrict the rollout ownership test to supplementary groups mapped in the Linux user namespace, skipping when no alternate group is available. - Exclude `gstcoreelements.dll` from the Windows startup-only voice fixture so handshakes succeed while runtime initialization still fails for missing plugins. GitOrigin-RevId: 618376705c49d6ee3eea09f0d089b2eff4623fd2 --- .../tests/suite/managed_proxy.rs | 21 ++++++++---- codex-rs/rollout/src/compression_tests.rs | 33 ++++++++++++++++--- codex-rs/voice-host/tests/installed_client.rs | 7 +++- 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/codex-rs/linux-sandbox/tests/suite/managed_proxy.rs b/codex-rs/linux-sandbox/tests/suite/managed_proxy.rs index 49f47f342a..16b13d9016 100644 --- a/codex-rs/linux-sandbox/tests/suite/managed_proxy.rs +++ b/codex-rs/linux-sandbox/tests/suite/managed_proxy.rs @@ -18,6 +18,7 @@ use codex_protocol::permissions::FileSystemSandboxPolicyContext; use codex_protocol::permissions::FileSystemSpecialPath; use codex_protocol::permissions::NetworkSandboxPolicy; use codex_utils_absolute_path::AbsolutePathBuf; +use codex_utils_cargo_bin::cargo_bin; use pretty_assertions::assert_eq; use std::collections::HashMap; use std::io::Read; @@ -180,7 +181,8 @@ fn linux_sandbox_command( args.push("--".to_string()); args.extend(command.iter().map(|entry| (*entry).to_string())); - let mut cmd = Command::new(env!("CARGO_BIN_EXE_codex-linux-sandbox")); + let mut cmd = + Command::new(cargo_bin("codex-linux-sandbox").expect("sandbox helper should exist")); cmd.args(args) .current_dir(cwd) .env_clear() @@ -396,7 +398,8 @@ printf 'legacy proc fallback\n' "CODEX_TEST_PROTECTED_FILE".to_string(), protected_file.display().to_string(), ); - let mut command = Command::new(env!("CARGO_BIN_EXE_codex-linux-sandbox")); + let mut command = + Command::new(cargo_bin("codex-linux-sandbox").expect("sandbox helper should exist")); command .arg("--sandbox-policy-cwd") .arg(std::env::current_dir().expect("current directory should exist")) @@ -474,9 +477,10 @@ async fn unsupported_system_bwrap_falls_back_to_bundled_bwrap() { let tempdir = tempfile::tempdir().expect("create isolated sandbox installation"); let sandbox_executable = tempdir.path().join("codex-linux-sandbox"); - let original_executable = env!("CARGO_BIN_EXE_codex-linux-sandbox"); - if std::fs::hard_link(original_executable, &sandbox_executable).is_err() { - codex_utils_cargo_bin::copy_executable(Path::new(original_executable), &sandbox_executable) + let original_executable = + cargo_bin("codex-linux-sandbox").expect("sandbox helper should exist"); + if std::fs::hard_link(&original_executable, &sandbox_executable).is_err() { + codex_utils_cargo_bin::copy_executable(&original_executable, &sandbox_executable) .expect("copy sandbox executable"); } @@ -795,7 +799,12 @@ async fn managed_proxy_mode_routes_through_bridge_and_blocks_direct_egress() { format!("http://127.0.0.1:{proxy_port}"), ); - let sandbox_helper_dir = std::path::Path::new(env!("CARGO_BIN_EXE_codex-linux-sandbox")) + // Bubblewrap re-executes the canonical binary, outside its Bazel runfiles alias. + let sandbox_helper = cargo_bin("codex-linux-sandbox") + .expect("sandbox helper should exist") + .canonicalize() + .expect("sandbox helper should resolve"); + let sandbox_helper_dir = sandbox_helper .parent() .expect("sandbox helper should have a parent"); let file_system_sandbox_policy = diff --git a/codex-rs/rollout/src/compression_tests.rs b/codex-rs/rollout/src/compression_tests.rs index 6f05b54366..83909df0e3 100644 --- a/codex-rs/rollout/src/compression_tests.rs +++ b/codex-rs/rollout/src/compression_tests.rs @@ -755,13 +755,36 @@ async fn worker_preserves_alternate_group_through_materialization() -> anyhow::R let original_group = fs::metadata(&path)?.gid(); let groups = Command::new("id").arg("-G").output()?; assert!(groups.status.success()); - let Some(group) = std::str::from_utf8(&groups.stdout)? + let groups = std::str::from_utf8(&groups.stdout)? .split_whitespace() .map(str::parse::) - .collect::, _>>()? - .into_iter() - .find(|group| *group != original_group) - else { + .collect::, _>>()?; + #[cfg(target_os = "linux")] + let groups = { + // Unmapped supplementary groups appear as the overflow GID in Bazel's + // user namespace, but chown cannot use them. + let gid_map = fs::read_to_string("/proc/self/gid_map")?; + let mapped_groups = gid_map + .lines() + .map(|line| { + let fields = line + .split_whitespace() + .map(str::parse::) + .collect::, _>>()?; + anyhow::ensure!(fields.len() == 3, "invalid GID mapping: {line}"); + Ok(fields[0]..fields[0] + fields[2]) + }) + .collect::>>()?; + groups + .into_iter() + .filter(|group| { + mapped_groups + .iter() + .any(|range| range.contains(&u64::from(*group))) + }) + .collect::>() + }; + let Some(group) = groups.into_iter().find(|group| *group != original_group) else { eprintln!("skipping ownership regression: no alternate supplementary group"); return Ok(()); }; diff --git a/codex-rs/voice-host/tests/installed_client.rs b/codex-rs/voice-host/tests/installed_client.rs index df6ba876fa..ed1d2d8d32 100644 --- a/codex-rs/voice-host/tests/installed_client.rs +++ b/codex-rs/voice-host/tests/installed_client.rs @@ -76,6 +76,11 @@ fn install_startup_libraries(runtime: &Path) -> Result<()> { fs::create_dir_all(&destination)?; for entry in fs::read_dir(source.join(libraries))? { let entry = entry?; + // Windows keeps plugins beside startup DLLs. Omit one required plugin + // so this startup-only fixture cannot initialize the audio runtime. + if cfg!(windows) && entry.file_name() == "gstcoreelements.dll" { + continue; + } if entry.path().is_file() { fs::copy(entry.path(), destination.join(entry.file_name()))?; } @@ -121,7 +126,7 @@ async fn installed_client_rejects_mixed_builds_and_missing_helper() -> Result<() .close() .await?; assert!(VoiceHost::connect(&package, "wrong-build").await.is_err()); - // Startup libraries permit handshakes; the missing runtime receipt prevents readiness. + // Startup libraries permit handshakes; missing native plugins prevent readiness. let host = VoiceHost::connect(&package, &build_commit().await?).await?; assert!(host.initialize_runtime().await.is_err()); // The same executable elsewhere in the package must not become a fallback.