mirror of
https://github.com/openai/codex.git
synced 2026-10-21 17:48:44 +00:00
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:
@@ -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
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
@@ -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}]}"#
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user