Move Linux sandbox unit tests into separate files (#55620)

## What changed

Extract the inline test modules for `bundled_bwrap`, `bwrap`, `exec_util`,
`launcher`, `proxy_routing`, and `seccomp` into sibling `*_tests.rs` files.
Keep them wired through `#[cfg(test)]` and explicit `#[path]` attributes,
with existing test coverage and runtime behavior unchanged.

GitOrigin-RevId: 79b70a092a19b10716939744542415bc1dcaf0b2
This commit is contained in:
Michael Bolin
2026-10-20 16:25:02 +00:00
committed by copyberry
parent 61469096fe
commit 5ac9888436
12 changed files with 2152 additions and 2146 deletions
+2 -125
View File
@@ -219,128 +219,5 @@ fn bytes_to_hex(bytes: &[u8; 32]) -> String {
}
#[cfg(test)]
mod tests {
use super::*;
use codex_install_context::CodexPackageLayout;
use codex_install_context::InstallContext;
use codex_install_context::InstallMethod;
use pretty_assertions::assert_eq;
use std::fs;
use tempfile::NamedTempFile;
use tempfile::tempdir;
#[test]
fn finds_package_layout_bwrap_from_install_context() {
let temp_dir = tempdir().expect("temp dir");
let package_dir = temp_dir.path();
let bin_dir = package_dir.join("bin");
let resources_dir = package_dir.join("codex-resources");
let expected_bwrap = resources_dir.join("bwrap");
fs::create_dir_all(&bin_dir).expect("create bin dir");
write_executable(&expected_bwrap);
let context = InstallContext {
method: InstallMethod::Other,
package_layout: Some(CodexPackageLayout {
package_dir: AbsolutePathBuf::from_absolute_path(package_dir).expect("absolute"),
bin_dir: AbsolutePathBuf::from_absolute_path(&bin_dir).expect("absolute"),
resources_dir: Some(
AbsolutePathBuf::from_absolute_path(&resources_dir).expect("absolute"),
),
path_dir: None,
}),
};
assert_eq!(
find_for_install_context(&context),
Some(AbsolutePathBuf::from_absolute_path(&expected_bwrap).expect("absolute"))
);
}
#[test]
fn finds_legacy_standalone_bundled_bwrap_next_to_exe_resources() {
let temp_dir = tempdir().expect("temp dir");
let exe = temp_dir.path().join("codex");
let expected_bwrap = temp_dir.path().join("codex-resources").join("bwrap");
write_executable(&exe);
write_executable(&expected_bwrap);
assert_eq!(
find_legacy_for_exe(&exe, /*bazel_candidate*/ None),
Some(AbsolutePathBuf::from_absolute_path(&expected_bwrap).expect("absolute"))
);
}
#[test]
fn finds_npm_bundled_bwrap_next_to_target_vendor_dir() {
let temp_dir = tempdir().expect("temp dir");
let target_dir = temp_dir.path().join("vendor/x86_64-unknown-linux-musl");
let exe = target_dir.join("codex").join("codex");
let expected_bwrap = target_dir.join("codex-resources").join("bwrap");
write_executable(&exe);
write_executable(&expected_bwrap);
assert_eq!(
find_legacy_for_exe(&exe, /*bazel_candidate*/ None),
Some(AbsolutePathBuf::from_absolute_path(&expected_bwrap).expect("absolute"))
);
}
#[test]
fn finds_adjacent_dev_bwrap() {
let temp_dir = tempdir().expect("temp dir");
let exe = temp_dir.path().join("codex");
let expected_bwrap = temp_dir.path().join("bwrap");
write_executable(&exe);
write_executable(&expected_bwrap);
assert_eq!(
find_legacy_for_exe(&exe, /*bazel_candidate*/ None),
Some(AbsolutePathBuf::from_absolute_path(&expected_bwrap).expect("absolute"))
);
}
#[test]
fn digest_verification_skips_missing_expected_digest() {
let file = NamedTempFile::new().expect("temp file");
fs::write(file.path(), b"contents").expect("write file");
verify_digest(file.as_file(), /*expected*/ None, file.path())
.expect("missing digest should skip verification");
}
#[test]
fn digest_verification_accepts_matching_digest() {
let file = NamedTempFile::new().expect("temp file");
fs::write(file.path(), b"contents").expect("write file");
let expected: [u8; 32] = Sha256::digest(b"contents").into();
verify_digest(file.as_file(), Some(expected), file.path())
.expect("matching digest should verify");
}
#[test]
fn digest_verification_rejects_mismatched_digest() {
let file = NamedTempFile::new().expect("temp file");
fs::write(file.path(), b"contents").expect("write file");
let err = verify_digest(file.as_file(), Some([0xab; 32]), file.path())
.expect_err("mismatched digest should fail");
assert!(err.contains("bundled bubblewrap digest mismatch"));
}
#[test]
fn parses_sha256_hex_digest() {
assert_eq!(parse_sha256_hex(&"ab".repeat(32)), Ok([0xab; 32]));
assert_eq!(parse_sha256_hex(&"00".repeat(32)), Ok(NULL_SHA256_DIGEST));
assert!(parse_sha256_hex("ab").is_err());
assert!(parse_sha256_hex(&format!("{}xx", "00".repeat(31))).is_err());
}
fn write_executable(path: &Path) {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).expect("create parent dir");
}
codex_utils_cargo_bin::write_executable(path, "").expect("write executable");
}
}
#[path = "bundled_bwrap_tests.rs"]
mod tests;
@@ -0,0 +1,125 @@
//! Verify bundled bubblewrap discovery and executable digest validation.
use super::*;
use codex_install_context::CodexPackageLayout;
use codex_install_context::InstallContext;
use codex_install_context::InstallMethod;
use pretty_assertions::assert_eq;
use std::fs;
use tempfile::NamedTempFile;
use tempfile::tempdir;
#[test]
fn finds_package_layout_bwrap_from_install_context() {
let temp_dir = tempdir().expect("temp dir");
let package_dir = temp_dir.path();
let bin_dir = package_dir.join("bin");
let resources_dir = package_dir.join("codex-resources");
let expected_bwrap = resources_dir.join("bwrap");
fs::create_dir_all(&bin_dir).expect("create bin dir");
write_executable(&expected_bwrap);
let context = InstallContext {
method: InstallMethod::Other,
package_layout: Some(CodexPackageLayout {
package_dir: AbsolutePathBuf::from_absolute_path(package_dir).expect("absolute"),
bin_dir: AbsolutePathBuf::from_absolute_path(&bin_dir).expect("absolute"),
resources_dir: Some(
AbsolutePathBuf::from_absolute_path(&resources_dir).expect("absolute"),
),
path_dir: None,
}),
};
assert_eq!(
find_for_install_context(&context),
Some(AbsolutePathBuf::from_absolute_path(&expected_bwrap).expect("absolute"))
);
}
#[test]
fn finds_legacy_standalone_bundled_bwrap_next_to_exe_resources() {
let temp_dir = tempdir().expect("temp dir");
let exe = temp_dir.path().join("codex");
let expected_bwrap = temp_dir.path().join("codex-resources").join("bwrap");
write_executable(&exe);
write_executable(&expected_bwrap);
assert_eq!(
find_legacy_for_exe(&exe, /*bazel_candidate*/ None),
Some(AbsolutePathBuf::from_absolute_path(&expected_bwrap).expect("absolute"))
);
}
#[test]
fn finds_npm_bundled_bwrap_next_to_target_vendor_dir() {
let temp_dir = tempdir().expect("temp dir");
let target_dir = temp_dir.path().join("vendor/x86_64-unknown-linux-musl");
let exe = target_dir.join("codex").join("codex");
let expected_bwrap = target_dir.join("codex-resources").join("bwrap");
write_executable(&exe);
write_executable(&expected_bwrap);
assert_eq!(
find_legacy_for_exe(&exe, /*bazel_candidate*/ None),
Some(AbsolutePathBuf::from_absolute_path(&expected_bwrap).expect("absolute"))
);
}
#[test]
fn finds_adjacent_dev_bwrap() {
let temp_dir = tempdir().expect("temp dir");
let exe = temp_dir.path().join("codex");
let expected_bwrap = temp_dir.path().join("bwrap");
write_executable(&exe);
write_executable(&expected_bwrap);
assert_eq!(
find_legacy_for_exe(&exe, /*bazel_candidate*/ None),
Some(AbsolutePathBuf::from_absolute_path(&expected_bwrap).expect("absolute"))
);
}
#[test]
fn digest_verification_skips_missing_expected_digest() {
let file = NamedTempFile::new().expect("temp file");
fs::write(file.path(), b"contents").expect("write file");
verify_digest(file.as_file(), /*expected*/ None, file.path())
.expect("missing digest should skip verification");
}
#[test]
fn digest_verification_accepts_matching_digest() {
let file = NamedTempFile::new().expect("temp file");
fs::write(file.path(), b"contents").expect("write file");
let expected: [u8; 32] = Sha256::digest(b"contents").into();
verify_digest(file.as_file(), Some(expected), file.path())
.expect("matching digest should verify");
}
#[test]
fn digest_verification_rejects_mismatched_digest() {
let file = NamedTempFile::new().expect("temp file");
fs::write(file.path(), b"contents").expect("write file");
let err = verify_digest(file.as_file(), Some([0xab; 32]), file.path())
.expect_err("mismatched digest should fail");
assert!(err.contains("bundled bubblewrap digest mismatch"));
}
#[test]
fn parses_sha256_hex_digest() {
assert_eq!(parse_sha256_hex(&"ab".repeat(32)), Ok([0xab; 32]));
assert_eq!(parse_sha256_hex(&"00".repeat(32)), Ok(NULL_SHA256_DIGEST));
assert!(parse_sha256_hex("ab").is_err());
assert!(parse_sha256_hex(&format!("{}xx", "00".repeat(31))).is_err());
}
fn write_executable(path: &Path) {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).expect("create parent dir");
}
codex_utils_cargo_bin::write_executable(path, "").expect("write executable");
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2 -35
View File
@@ -40,38 +40,5 @@ fn clear_cloexec(fd: libc::c_int) {
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use tempfile::NamedTempFile;
#[test]
fn preserved_files_are_made_inheritable() {
let file = NamedTempFile::new().expect("temp file");
set_cloexec(file.as_file().as_raw_fd());
make_files_inheritable(std::slice::from_ref(file.as_file()));
assert_eq!(fd_flags(file.as_file().as_raw_fd()) & libc::FD_CLOEXEC, 0);
}
fn set_cloexec(fd: libc::c_int) {
let flags = fd_flags(fd);
// SAFETY: `fd` is valid for the duration of the test.
let result = unsafe { libc::fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC) };
if result < 0 {
let err = std::io::Error::last_os_error();
panic!("failed to set CLOEXEC for test fd {fd}: {err}");
}
}
fn fd_flags(fd: libc::c_int) -> libc::c_int {
// SAFETY: `fd` is valid for the duration of the test.
let flags = unsafe { libc::fcntl(fd, libc::F_GETFD) };
if flags < 0 {
let err = std::io::Error::last_os_error();
panic!("failed to read fd flags for test fd {fd}: {err}");
}
flags
}
}
#[path = "exec_util_tests.rs"]
mod tests;
@@ -0,0 +1,35 @@
//! Verify preserved file descriptors remain inheritable across exec.
use super::*;
use pretty_assertions::assert_eq;
use tempfile::NamedTempFile;
#[test]
fn preserved_files_are_made_inheritable() {
let file = NamedTempFile::new().expect("temp file");
set_cloexec(file.as_file().as_raw_fd());
make_files_inheritable(std::slice::from_ref(file.as_file()));
assert_eq!(fd_flags(file.as_file().as_raw_fd()) & libc::FD_CLOEXEC, 0);
}
fn set_cloexec(fd: libc::c_int) {
let flags = fd_flags(fd);
// SAFETY: `fd` is valid for the duration of the test.
let result = unsafe { libc::fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC) };
if result < 0 {
let err = std::io::Error::last_os_error();
panic!("failed to set CLOEXEC for test fd {fd}: {err}");
}
}
fn fd_flags(fd: libc::c_int) -> libc::c_int {
// SAFETY: `fd` is valid for the duration of the test.
let flags = unsafe { libc::fcntl(fd, libc::F_GETFD) };
if flags < 0 {
let err = std::io::Error::last_os_error();
panic!("failed to read fd flags for test fd {fd}: {err}");
}
flags
}
+2 -223
View File
@@ -248,226 +248,5 @@ fn exec_system_bwrap(
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use tempfile::NamedTempFile;
#[test]
fn prefers_system_bwrap_when_help_lists_argv0() {
let fake_bwrap = NamedTempFile::new().expect("temp file");
let fake_bwrap_path = fake_bwrap.path();
let expected = AbsolutePathBuf::from_absolute_path(fake_bwrap_path).expect("absolute");
assert_eq!(
system_bwrap_launcher_for_path_with_probe(fake_bwrap_path, |_| {
Some(SystemBwrapCapabilities {
supports_argv0: true,
supports_perms: true,
supports_ro_bind_fd: true,
})
}),
Some(SystemBwrapLauncher {
program: expected,
supports_argv0: true,
supports_ro_bind_fd: true,
})
);
}
#[test]
fn prefers_system_bwrap_when_system_bwrap_lacks_argv0() {
let fake_bwrap = NamedTempFile::new().expect("temp file");
let fake_bwrap_path = fake_bwrap.path();
assert_eq!(
system_bwrap_launcher_for_path_with_probe(fake_bwrap_path, |_| {
Some(SystemBwrapCapabilities {
supports_argv0: false,
supports_perms: true,
supports_ro_bind_fd: false,
})
}),
Some(SystemBwrapLauncher {
program: AbsolutePathBuf::from_absolute_path(fake_bwrap_path).expect("absolute"),
supports_argv0: false,
supports_ro_bind_fd: false,
})
);
}
#[test]
fn ignores_system_bwrap_when_system_bwrap_lacks_perms() {
let fake_bwrap = NamedTempFile::new().expect("temp file");
assert_eq!(
system_bwrap_launcher_for_path_with_probe(fake_bwrap.path(), |_| {
Some(SystemBwrapCapabilities {
supports_argv0: false,
supports_perms: false,
supports_ro_bind_fd: false,
})
}),
None
);
}
#[test]
fn detects_fd_backed_read_only_mount_support_in_system_bwrap_help() {
let temp_dir = tempfile::tempdir().expect("temp directory");
let fake_bwrap_path = temp_dir.path().join("bwrap");
codex_utils_cargo_bin::write_executable(
&fake_bwrap_path,
"#!/bin/sh\nprintf '%s\\n' '--as-pid-1' '--perms' '--argv0' '--ro-bind-fd'\n",
)
.expect("write fake bubblewrap");
assert_eq!(
system_bwrap_capabilities(&fake_bwrap_path),
Some(SystemBwrapCapabilities {
supports_argv0: true,
supports_perms: true,
supports_ro_bind_fd: true,
})
);
}
#[test]
fn translates_fd_mounts_for_legacy_system_bubblewrap() {
let mut argv = vec![
"bwrap".to_string(),
"--ro-bind-fd".to_string(),
"7".to_string(),
"/tmp/socket-root".to_string(),
"--".to_string(),
"/usr/bin/codex-linux-sandbox".to_string(),
"--apply-seccomp-then-exec".to_string(),
"--".to_string(),
"echo".to_string(),
"--ro-bind-fd".to_string(),
];
translate_legacy_bwrap_fd_mounts(&mut argv).expect("fd mount should translate");
assert_eq!(
argv,
vec![
"bwrap".to_string(),
"--ro-bind".to_string(),
"/proc/self/fd/7".to_string(),
"/tmp/socket-root".to_string(),
"--".to_string(),
"/usr/bin/codex-linux-sandbox".to_string(),
"--verify-fd-mount".to_string(),
"7:/tmp/socket-root".to_string(),
"--apply-seccomp-then-exec".to_string(),
"--".to_string(),
"echo".to_string(),
"--ro-bind-fd".to_string(),
]
);
}
#[test]
fn translates_multiple_fd_mounts_for_legacy_system_bubblewrap() {
let mut argv = vec![
"bwrap".to_string(),
"--ro-bind-fd".to_string(),
"7".to_string(),
"/tmp/first".to_string(),
"--ro-bind-fd".to_string(),
"9".to_string(),
"/tmp/second:with-colon".to_string(),
"--".to_string(),
"codex-linux-sandbox".to_string(),
"--apply-seccomp-then-exec".to_string(),
"--".to_string(),
"true".to_string(),
];
translate_legacy_bwrap_fd_mounts(&mut argv).expect("fd mounts should translate");
assert_eq!(
argv,
vec![
"bwrap".to_string(),
"--ro-bind".to_string(),
"/proc/self/fd/7".to_string(),
"/tmp/first".to_string(),
"--ro-bind".to_string(),
"/proc/self/fd/9".to_string(),
"/tmp/second:with-colon".to_string(),
"--".to_string(),
"codex-linux-sandbox".to_string(),
"--verify-fd-mount".to_string(),
"7:/tmp/first".to_string(),
"--verify-fd-mount".to_string(),
"9:/tmp/second:with-colon".to_string(),
"--apply-seccomp-then-exec".to_string(),
"--".to_string(),
"true".to_string(),
]
);
}
#[test]
fn rejects_malformed_legacy_bubblewrap_fd_mounts() {
for (fd, destination) in [
("invalid", "/tmp/socket-root"),
("2", "/tmp/socket-root"),
("7", "relative/socket-root"),
] {
let mut argv = vec![
"bwrap".to_string(),
"--ro-bind-fd".to_string(),
fd.to_string(),
destination.to_string(),
"--".to_string(),
"codex-linux-sandbox".to_string(),
];
assert!(translate_legacy_bwrap_fd_mounts(&mut argv).is_err());
}
}
#[test]
fn rejects_fd_mounts_without_the_trusted_inner_sandbox_stage() {
let mut argv = vec![
"bwrap".to_string(),
"--ro-bind-fd".to_string(),
"7".to_string(),
"/tmp/socket-root".to_string(),
"--".to_string(),
"/bin/true".to_string(),
"--".to_string(),
"--apply-seccomp-then-exec".to_string(),
];
assert!(translate_legacy_bwrap_fd_mounts(&mut argv).is_err());
}
#[test]
fn rejects_duplicate_legacy_bubblewrap_fd_mounts() {
let mut argv = vec![
"bwrap".to_string(),
"--ro-bind-fd".to_string(),
"7".to_string(),
"/tmp/first".to_string(),
"--ro-bind-fd".to_string(),
"7".to_string(),
"/tmp/second".to_string(),
"--".to_string(),
"codex-linux-sandbox".to_string(),
];
assert!(translate_legacy_bwrap_fd_mounts(&mut argv).is_err());
}
#[test]
fn ignores_system_bwrap_when_system_bwrap_is_missing() {
assert_eq!(
system_bwrap_launcher_for_path(Path::new("/definitely/not/a/bwrap")),
None
);
}
}
#[path = "launcher_tests.rs"]
mod tests;
@@ -0,0 +1,223 @@
//! Verify system bubblewrap selection and legacy fd mount translation.
use super::*;
use pretty_assertions::assert_eq;
use tempfile::NamedTempFile;
#[test]
fn prefers_system_bwrap_when_help_lists_argv0() {
let fake_bwrap = NamedTempFile::new().expect("temp file");
let fake_bwrap_path = fake_bwrap.path();
let expected = AbsolutePathBuf::from_absolute_path(fake_bwrap_path).expect("absolute");
assert_eq!(
system_bwrap_launcher_for_path_with_probe(fake_bwrap_path, |_| {
Some(SystemBwrapCapabilities {
supports_argv0: true,
supports_perms: true,
supports_ro_bind_fd: true,
})
}),
Some(SystemBwrapLauncher {
program: expected,
supports_argv0: true,
supports_ro_bind_fd: true,
})
);
}
#[test]
fn prefers_system_bwrap_when_system_bwrap_lacks_argv0() {
let fake_bwrap = NamedTempFile::new().expect("temp file");
let fake_bwrap_path = fake_bwrap.path();
assert_eq!(
system_bwrap_launcher_for_path_with_probe(fake_bwrap_path, |_| {
Some(SystemBwrapCapabilities {
supports_argv0: false,
supports_perms: true,
supports_ro_bind_fd: false,
})
}),
Some(SystemBwrapLauncher {
program: AbsolutePathBuf::from_absolute_path(fake_bwrap_path).expect("absolute"),
supports_argv0: false,
supports_ro_bind_fd: false,
})
);
}
#[test]
fn ignores_system_bwrap_when_system_bwrap_lacks_perms() {
let fake_bwrap = NamedTempFile::new().expect("temp file");
assert_eq!(
system_bwrap_launcher_for_path_with_probe(fake_bwrap.path(), |_| {
Some(SystemBwrapCapabilities {
supports_argv0: false,
supports_perms: false,
supports_ro_bind_fd: false,
})
}),
None
);
}
#[test]
fn detects_fd_backed_read_only_mount_support_in_system_bwrap_help() {
let temp_dir = tempfile::tempdir().expect("temp directory");
let fake_bwrap_path = temp_dir.path().join("bwrap");
codex_utils_cargo_bin::write_executable(
&fake_bwrap_path,
"#!/bin/sh\nprintf '%s\\n' '--as-pid-1' '--perms' '--argv0' '--ro-bind-fd'\n",
)
.expect("write fake bubblewrap");
assert_eq!(
system_bwrap_capabilities(&fake_bwrap_path),
Some(SystemBwrapCapabilities {
supports_argv0: true,
supports_perms: true,
supports_ro_bind_fd: true,
})
);
}
#[test]
fn translates_fd_mounts_for_legacy_system_bubblewrap() {
let mut argv = vec![
"bwrap".to_string(),
"--ro-bind-fd".to_string(),
"7".to_string(),
"/tmp/socket-root".to_string(),
"--".to_string(),
"/usr/bin/codex-linux-sandbox".to_string(),
"--apply-seccomp-then-exec".to_string(),
"--".to_string(),
"echo".to_string(),
"--ro-bind-fd".to_string(),
];
translate_legacy_bwrap_fd_mounts(&mut argv).expect("fd mount should translate");
assert_eq!(
argv,
vec![
"bwrap".to_string(),
"--ro-bind".to_string(),
"/proc/self/fd/7".to_string(),
"/tmp/socket-root".to_string(),
"--".to_string(),
"/usr/bin/codex-linux-sandbox".to_string(),
"--verify-fd-mount".to_string(),
"7:/tmp/socket-root".to_string(),
"--apply-seccomp-then-exec".to_string(),
"--".to_string(),
"echo".to_string(),
"--ro-bind-fd".to_string(),
]
);
}
#[test]
fn translates_multiple_fd_mounts_for_legacy_system_bubblewrap() {
let mut argv = vec![
"bwrap".to_string(),
"--ro-bind-fd".to_string(),
"7".to_string(),
"/tmp/first".to_string(),
"--ro-bind-fd".to_string(),
"9".to_string(),
"/tmp/second:with-colon".to_string(),
"--".to_string(),
"codex-linux-sandbox".to_string(),
"--apply-seccomp-then-exec".to_string(),
"--".to_string(),
"true".to_string(),
];
translate_legacy_bwrap_fd_mounts(&mut argv).expect("fd mounts should translate");
assert_eq!(
argv,
vec![
"bwrap".to_string(),
"--ro-bind".to_string(),
"/proc/self/fd/7".to_string(),
"/tmp/first".to_string(),
"--ro-bind".to_string(),
"/proc/self/fd/9".to_string(),
"/tmp/second:with-colon".to_string(),
"--".to_string(),
"codex-linux-sandbox".to_string(),
"--verify-fd-mount".to_string(),
"7:/tmp/first".to_string(),
"--verify-fd-mount".to_string(),
"9:/tmp/second:with-colon".to_string(),
"--apply-seccomp-then-exec".to_string(),
"--".to_string(),
"true".to_string(),
]
);
}
#[test]
fn rejects_malformed_legacy_bubblewrap_fd_mounts() {
for (fd, destination) in [
("invalid", "/tmp/socket-root"),
("2", "/tmp/socket-root"),
("7", "relative/socket-root"),
] {
let mut argv = vec![
"bwrap".to_string(),
"--ro-bind-fd".to_string(),
fd.to_string(),
destination.to_string(),
"--".to_string(),
"codex-linux-sandbox".to_string(),
];
assert!(translate_legacy_bwrap_fd_mounts(&mut argv).is_err());
}
}
#[test]
fn rejects_fd_mounts_without_the_trusted_inner_sandbox_stage() {
let mut argv = vec![
"bwrap".to_string(),
"--ro-bind-fd".to_string(),
"7".to_string(),
"/tmp/socket-root".to_string(),
"--".to_string(),
"/bin/true".to_string(),
"--".to_string(),
"--apply-seccomp-then-exec".to_string(),
];
assert!(translate_legacy_bwrap_fd_mounts(&mut argv).is_err());
}
#[test]
fn rejects_duplicate_legacy_bubblewrap_fd_mounts() {
let mut argv = vec![
"bwrap".to_string(),
"--ro-bind-fd".to_string(),
"7".to_string(),
"/tmp/first".to_string(),
"--ro-bind-fd".to_string(),
"7".to_string(),
"/tmp/second".to_string(),
"--".to_string(),
"codex-linux-sandbox".to_string(),
];
assert!(translate_legacy_bwrap_fd_mounts(&mut argv).is_err());
}
#[test]
fn ignores_system_bwrap_when_system_bwrap_is_missing() {
assert_eq!(
system_bwrap_launcher_for_path(Path::new("/definitely/not/a/bwrap")),
None
);
}
+2 -129
View File
@@ -487,132 +487,5 @@ fn proxy_bidirectional(mut upstream: TcpStream, mut client: TcpStream) -> io::Re
}
#[cfg(test)]
mod tests {
use super::PROXY_ATTRIBUTION_TOKEN_ENV_KEY;
use super::ProxyRouteEntry;
use super::ProxyRouteSpec;
use super::default_proxy_port;
use super::extract_attribution_token_and_plan;
use super::is_proxy_env_key;
use super::parse_loopback_proxy_endpoint;
use super::plan_proxy_routes;
use super::rewrite_proxy_env_value;
use pretty_assertions::assert_eq;
use std::collections::HashMap;
use std::net::SocketAddr;
#[test]
fn recognizes_proxy_env_keys_case_insensitively() {
assert_eq!(is_proxy_env_key("HTTP_PROXY"), true);
assert_eq!(is_proxy_env_key("http_proxy"), true);
assert_eq!(is_proxy_env_key("WS_PROXY"), true);
assert_eq!(is_proxy_env_key("wss_proxy"), true);
assert_eq!(is_proxy_env_key("PATH"), false);
}
#[test]
fn parses_loopback_proxy_endpoint() {
let endpoint = parse_loopback_proxy_endpoint("http://127.0.0.1:43128");
assert_eq!(
endpoint,
Some(
"127.0.0.1:43128"
.parse::<SocketAddr>()
.expect("valid socket")
)
);
}
#[test]
fn ignores_non_loopback_proxy_endpoint() {
assert_eq!(
parse_loopback_proxy_endpoint("http://example.com:3128"),
None
);
}
#[test]
fn plan_proxy_routes_only_includes_valid_loopback_endpoints() {
let mut env = HashMap::new();
env.insert(
"HTTP_PROXY".to_string(),
"http://127.0.0.1:43128".to_string(),
);
env.insert(
"HTTPS_PROXY".to_string(),
"http://example.com:3128".to_string(),
);
env.insert("PATH".to_string(), "/usr/bin".to_string());
let plan = plan_proxy_routes(&env);
assert_eq!(plan.has_proxy_config, true);
assert_eq!(plan.routes.len(), 1);
assert_eq!(plan.routes[0].env_key, "HTTP_PROXY");
assert_eq!(
plan.routes[0].endpoint,
"127.0.0.1:43128"
.parse::<SocketAddr>()
.expect("valid socket")
);
}
#[test]
fn attribution_token_is_extracted_before_proxy_route_planning() {
let mut env = HashMap::new();
env.insert(
"HTTP_PROXY".to_string(),
"http://127.0.0.1:43128".to_string(),
);
env.insert(
PROXY_ATTRIBUTION_TOKEN_ENV_KEY.to_string(),
"exec-token".to_string(),
);
let (attribution_token, plan) = extract_attribution_token_and_plan(env);
assert_eq!(attribution_token.as_deref(), Some("exec-token"));
assert_eq!(
plan,
super::ProxyRoutePlan {
routes: vec![super::PlannedProxyRoute {
env_key: "HTTP_PROXY".to_string(),
endpoint: "127.0.0.1:43128"
.parse::<SocketAddr>()
.expect("valid socket"),
}],
has_proxy_config: true,
}
);
}
#[test]
fn rewrites_proxy_url_to_local_loopback_port() {
let rewritten =
rewrite_proxy_env_value("socks5h://127.0.0.1:8081", /*local_port*/ 43210)
.expect("rewritten value");
assert_eq!(rewritten, "socks5h://127.0.0.1:43210");
}
#[test]
fn default_proxy_ports_match_expected_schemes() {
assert_eq!(default_proxy_port("http"), 80);
assert_eq!(default_proxy_port("https"), 443);
assert_eq!(default_proxy_port("socks5h"), 1080);
}
#[test]
fn proxy_route_spec_serialization_omits_proxy_urls() {
let spec = ProxyRouteSpec {
routes: vec![ProxyRouteEntry {
env_key: "HTTP_PROXY".to_string(),
control_fd: 3,
}],
};
let serialized = serde_json::to_string(&spec).expect("proxy route spec should serialize");
assert_eq!(
serialized,
r#"{"routes":[{"env_key":"HTTP_PROXY","control_fd":3}]}"#
);
}
}
#[path = "proxy_routing_tests.rs"]
mod tests;
@@ -0,0 +1,128 @@
//! Verify proxy route planning, attribution handling, and URL rewriting.
use super::PROXY_ATTRIBUTION_TOKEN_ENV_KEY;
use super::ProxyRouteEntry;
use super::ProxyRouteSpec;
use super::default_proxy_port;
use super::extract_attribution_token_and_plan;
use super::is_proxy_env_key;
use super::parse_loopback_proxy_endpoint;
use super::plan_proxy_routes;
use super::rewrite_proxy_env_value;
use pretty_assertions::assert_eq;
use std::collections::HashMap;
use std::net::SocketAddr;
#[test]
fn recognizes_proxy_env_keys_case_insensitively() {
assert_eq!(is_proxy_env_key("HTTP_PROXY"), true);
assert_eq!(is_proxy_env_key("http_proxy"), true);
assert_eq!(is_proxy_env_key("WS_PROXY"), true);
assert_eq!(is_proxy_env_key("wss_proxy"), true);
assert_eq!(is_proxy_env_key("PATH"), false);
}
#[test]
fn parses_loopback_proxy_endpoint() {
let endpoint = parse_loopback_proxy_endpoint("http://127.0.0.1:43128");
assert_eq!(
endpoint,
Some(
"127.0.0.1:43128"
.parse::<SocketAddr>()
.expect("valid socket")
)
);
}
#[test]
fn ignores_non_loopback_proxy_endpoint() {
assert_eq!(
parse_loopback_proxy_endpoint("http://example.com:3128"),
None
);
}
#[test]
fn plan_proxy_routes_only_includes_valid_loopback_endpoints() {
let mut env = HashMap::new();
env.insert(
"HTTP_PROXY".to_string(),
"http://127.0.0.1:43128".to_string(),
);
env.insert(
"HTTPS_PROXY".to_string(),
"http://example.com:3128".to_string(),
);
env.insert("PATH".to_string(), "/usr/bin".to_string());
let plan = plan_proxy_routes(&env);
assert_eq!(plan.has_proxy_config, true);
assert_eq!(plan.routes.len(), 1);
assert_eq!(plan.routes[0].env_key, "HTTP_PROXY");
assert_eq!(
plan.routes[0].endpoint,
"127.0.0.1:43128"
.parse::<SocketAddr>()
.expect("valid socket")
);
}
#[test]
fn attribution_token_is_extracted_before_proxy_route_planning() {
let mut env = HashMap::new();
env.insert(
"HTTP_PROXY".to_string(),
"http://127.0.0.1:43128".to_string(),
);
env.insert(
PROXY_ATTRIBUTION_TOKEN_ENV_KEY.to_string(),
"exec-token".to_string(),
);
let (attribution_token, plan) = extract_attribution_token_and_plan(env);
assert_eq!(attribution_token.as_deref(), Some("exec-token"));
assert_eq!(
plan,
super::ProxyRoutePlan {
routes: vec![super::PlannedProxyRoute {
env_key: "HTTP_PROXY".to_string(),
endpoint: "127.0.0.1:43128"
.parse::<SocketAddr>()
.expect("valid socket"),
}],
has_proxy_config: true,
}
);
}
#[test]
fn rewrites_proxy_url_to_local_loopback_port() {
let rewritten = rewrite_proxy_env_value("socks5h://127.0.0.1:8081", /*local_port*/ 43210)
.expect("rewritten value");
assert_eq!(rewritten, "socks5h://127.0.0.1:43210");
}
#[test]
fn default_proxy_ports_match_expected_schemes() {
assert_eq!(default_proxy_port("http"), 80);
assert_eq!(default_proxy_port("https"), 443);
assert_eq!(default_proxy_port("socks5h"), 1080);
}
#[test]
fn proxy_route_spec_serialization_omits_proxy_urls() {
let spec = ProxyRouteSpec {
routes: vec![ProxyRouteEntry {
env_key: "HTTP_PROXY".to_string(),
control_fd: 3,
}],
};
let serialized = serde_json::to_string(&spec).expect("proxy route spec should serialize");
assert_eq!(
serialized,
r#"{"routes":[{"env_key":"HTTP_PROXY","control_fd":3}]}"#
);
}
+2 -77
View File
@@ -302,80 +302,5 @@ fn install_network_seccomp_filter_on_current_thread(
}
#[cfg(test)]
mod tests {
use super::NetworkSeccompMode;
use super::network_seccomp_mode;
use super::should_install_network_seccomp;
use codex_protocol::protocol::NetworkSandboxPolicy;
use pretty_assertions::assert_eq;
#[test]
fn managed_network_enforces_seccomp_even_for_full_network_policy() {
assert_eq!(
should_install_network_seccomp(
NetworkSandboxPolicy::Enabled,
/*allow_network_for_proxy*/ true,
),
true
);
}
#[test]
fn full_network_policy_without_managed_network_skips_seccomp() {
assert_eq!(
should_install_network_seccomp(
NetworkSandboxPolicy::Enabled,
/*allow_network_for_proxy*/ false,
),
false
);
}
#[test]
fn restricted_network_policy_always_installs_seccomp() {
assert!(should_install_network_seccomp(
NetworkSandboxPolicy::Restricted,
/*allow_network_for_proxy*/ false,
));
assert!(should_install_network_seccomp(
NetworkSandboxPolicy::Restricted,
/*allow_network_for_proxy*/ true,
));
}
#[test]
fn managed_proxy_routes_use_proxy_routed_seccomp_mode() {
assert_eq!(
network_seccomp_mode(
NetworkSandboxPolicy::Enabled,
/*allow_network_for_proxy*/ true,
/*proxy_routed_network*/ true,
),
Some(NetworkSeccompMode::ProxyRouted)
);
}
#[test]
fn restricted_network_without_proxy_routing_uses_restricted_mode() {
assert_eq!(
network_seccomp_mode(
NetworkSandboxPolicy::Restricted,
/*allow_network_for_proxy*/ false,
/*proxy_routed_network*/ false,
),
Some(NetworkSeccompMode::Restricted)
);
}
#[test]
fn full_network_without_managed_proxy_skips_network_seccomp_mode() {
assert_eq!(
network_seccomp_mode(
NetworkSandboxPolicy::Enabled,
/*allow_network_for_proxy*/ false,
/*proxy_routed_network*/ false,
),
None
);
}
}
#[path = "seccomp_tests.rs"]
mod tests;
@@ -0,0 +1,77 @@
//! Verify network policies select the expected seccomp enforcement mode.
use super::NetworkSeccompMode;
use super::network_seccomp_mode;
use super::should_install_network_seccomp;
use codex_protocol::protocol::NetworkSandboxPolicy;
use pretty_assertions::assert_eq;
#[test]
fn managed_network_enforces_seccomp_even_for_full_network_policy() {
assert_eq!(
should_install_network_seccomp(
NetworkSandboxPolicy::Enabled,
/*allow_network_for_proxy*/ true,
),
true
);
}
#[test]
fn full_network_policy_without_managed_network_skips_seccomp() {
assert_eq!(
should_install_network_seccomp(
NetworkSandboxPolicy::Enabled,
/*allow_network_for_proxy*/ false,
),
false
);
}
#[test]
fn restricted_network_policy_always_installs_seccomp() {
assert!(should_install_network_seccomp(
NetworkSandboxPolicy::Restricted,
/*allow_network_for_proxy*/ false,
));
assert!(should_install_network_seccomp(
NetworkSandboxPolicy::Restricted,
/*allow_network_for_proxy*/ true,
));
}
#[test]
fn managed_proxy_routes_use_proxy_routed_seccomp_mode() {
assert_eq!(
network_seccomp_mode(
NetworkSandboxPolicy::Enabled,
/*allow_network_for_proxy*/ true,
/*proxy_routed_network*/ true,
),
Some(NetworkSeccompMode::ProxyRouted)
);
}
#[test]
fn restricted_network_without_proxy_routing_uses_restricted_mode() {
assert_eq!(
network_seccomp_mode(
NetworkSandboxPolicy::Restricted,
/*allow_network_for_proxy*/ false,
/*proxy_routed_network*/ false,
),
Some(NetworkSeccompMode::Restricted)
);
}
#[test]
fn full_network_without_managed_proxy_skips_network_seccomp_mode() {
assert_eq!(
network_seccomp_mode(
NetworkSandboxPolicy::Enabled,
/*allow_network_for_proxy*/ false,
/*proxy_routed_network*/ false,
),
None
);
}