mirror of
https://github.com/openai/codex.git
synced 2026-05-02 02:17:22 +00:00
exec tests: launch sandbox cases from permission profiles
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#![cfg(unix)]
|
||||
use codex_core::spawn::StdioPolicy;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_absolute_path::test_support::PathBufExt;
|
||||
use std::collections::HashMap;
|
||||
@@ -14,7 +15,7 @@ use tokio::process::Child;
|
||||
async fn spawn_command_under_sandbox(
|
||||
command: Vec<String>,
|
||||
command_cwd: AbsolutePathBuf,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
permission_profile: &PermissionProfile,
|
||||
sandbox_cwd: &AbsolutePathBuf,
|
||||
stdio_policy: StdioPolicy,
|
||||
env: HashMap<String, String>,
|
||||
@@ -24,7 +25,6 @@ async fn spawn_command_under_sandbox(
|
||||
use codex_core::exec::build_exec_request;
|
||||
use codex_core::sandboxing::SandboxPermissions;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use std::process::Stdio;
|
||||
|
||||
let codex_linux_sandbox_exe = None;
|
||||
@@ -42,7 +42,7 @@ async fn spawn_command_under_sandbox(
|
||||
justification: None,
|
||||
arg0: None,
|
||||
},
|
||||
&PermissionProfile::from_legacy_sandbox_policy(sandbox_policy),
|
||||
permission_profile,
|
||||
sandbox_cwd,
|
||||
&codex_linux_sandbox_exe,
|
||||
/*use_legacy_landlock*/ false,
|
||||
@@ -83,22 +83,20 @@ async fn spawn_command_under_sandbox(
|
||||
async fn spawn_command_under_sandbox(
|
||||
command: Vec<String>,
|
||||
command_cwd: AbsolutePathBuf,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
permission_profile: &PermissionProfile,
|
||||
sandbox_cwd: &AbsolutePathBuf,
|
||||
stdio_policy: StdioPolicy,
|
||||
env: HashMap<String, String>,
|
||||
) -> std::io::Result<Child> {
|
||||
use codex_core::spawn_command_under_linux_sandbox;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
|
||||
let codex_linux_sandbox_exe = core_test_support::find_codex_linux_sandbox_exe()
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::NotFound, err))?;
|
||||
let permission_profile = PermissionProfile::from_legacy_sandbox_policy(sandbox_policy);
|
||||
spawn_command_under_linux_sandbox(
|
||||
codex_linux_sandbox_exe,
|
||||
command,
|
||||
command_cwd,
|
||||
&permission_profile,
|
||||
permission_profile,
|
||||
sandbox_cwd,
|
||||
/*use_legacy_landlock*/ false,
|
||||
stdio_policy,
|
||||
@@ -118,9 +116,16 @@ async fn spawn_command_under_sandbox(
|
||||
async fn linux_sandbox_test_env() -> Option<HashMap<String, String>> {
|
||||
let command_cwd = AbsolutePathBuf::current_dir().ok()?;
|
||||
let sandbox_cwd = command_cwd.clone();
|
||||
let policy = SandboxPolicy::new_read_only_policy();
|
||||
let permission_profile = PermissionProfile::read_only();
|
||||
|
||||
if can_apply_linux_sandbox_policy(&policy, &command_cwd, &sandbox_cwd, HashMap::new()).await {
|
||||
if can_apply_linux_sandbox_policy(
|
||||
&permission_profile,
|
||||
&command_cwd,
|
||||
&sandbox_cwd,
|
||||
HashMap::new(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
return Some(HashMap::new());
|
||||
}
|
||||
|
||||
@@ -135,7 +140,7 @@ async fn linux_sandbox_test_env() -> Option<HashMap<String, String>> {
|
||||
/// This is used as a capability probe so sandbox behavior tests only run when
|
||||
/// Landlock enforcement is actually active.
|
||||
async fn can_apply_linux_sandbox_policy(
|
||||
policy: &SandboxPolicy,
|
||||
permission_profile: &PermissionProfile,
|
||||
command_cwd: &AbsolutePathBuf,
|
||||
sandbox_cwd: &AbsolutePathBuf,
|
||||
env: HashMap<String, String>,
|
||||
@@ -143,7 +148,7 @@ async fn can_apply_linux_sandbox_policy(
|
||||
let spawn_result = spawn_command_under_sandbox(
|
||||
vec!["/usr/bin/true".to_string()],
|
||||
command_cwd.clone(),
|
||||
policy,
|
||||
permission_profile,
|
||||
sandbox_cwd,
|
||||
StdioPolicy::RedirectForShellTool,
|
||||
env,
|
||||
@@ -180,12 +185,12 @@ async fn python_multiprocessing_lock_works_under_sandbox() {
|
||||
#[cfg(target_os = "linux")]
|
||||
let writable_roots: Vec<AbsolutePathBuf> = vec!["/dev/shm".try_into().unwrap()];
|
||||
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access: false,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
};
|
||||
let permission_profile = PermissionProfile::workspace_write_with(
|
||||
&writable_roots,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
/*exclude_tmpdir_env_var*/ false,
|
||||
/*exclude_slash_tmp*/ false,
|
||||
);
|
||||
|
||||
let python_code = r#"import multiprocessing
|
||||
from multiprocessing import Lock, Process
|
||||
@@ -210,7 +215,7 @@ if __name__ == '__main__':
|
||||
python_code.to_string(),
|
||||
],
|
||||
command_cwd,
|
||||
&policy,
|
||||
&permission_profile,
|
||||
&sandbox_cwd,
|
||||
StdioPolicy::Inherit,
|
||||
sandbox_env,
|
||||
@@ -242,7 +247,7 @@ async fn python_getpwuid_works_under_sandbox() {
|
||||
return;
|
||||
}
|
||||
|
||||
let policy = SandboxPolicy::new_read_only_policy();
|
||||
let permission_profile = PermissionProfile::read_only();
|
||||
let command_cwd = AbsolutePathBuf::current_dir().expect("should be able to get current dir");
|
||||
let sandbox_cwd = command_cwd.clone();
|
||||
|
||||
@@ -253,7 +258,7 @@ async fn python_getpwuid_works_under_sandbox() {
|
||||
"import pwd, os; print(pwd.getpwuid(os.getuid()))".to_string(),
|
||||
],
|
||||
command_cwd,
|
||||
&policy,
|
||||
&permission_profile,
|
||||
&sandbox_cwd,
|
||||
StdioPolicy::RedirectForShellTool,
|
||||
sandbox_env,
|
||||
@@ -294,12 +299,12 @@ async fn sandbox_distinguishes_command_and_policy_cwds() {
|
||||
// Note writable_roots is empty: verify that `canonical_allowed_path` is
|
||||
// writable only because it is under the sandbox policy cwd, not because it
|
||||
// is under a writable root.
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
let permission_profile = PermissionProfile::workspace_write_with(
|
||||
&[],
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
/*exclude_tmpdir_env_var*/ true,
|
||||
/*exclude_slash_tmp*/ true,
|
||||
);
|
||||
|
||||
// Attempt to write inside the command cwd, which is outside of the sandbox policy cwd.
|
||||
let mut child = spawn_command_under_sandbox(
|
||||
@@ -309,7 +314,7 @@ async fn sandbox_distinguishes_command_and_policy_cwds() {
|
||||
"echo forbidden > forbidden.txt".to_string(),
|
||||
],
|
||||
command_root.clone(),
|
||||
&policy,
|
||||
&permission_profile,
|
||||
&canonical_sandbox_root,
|
||||
StdioPolicy::Inherit,
|
||||
sandbox_env.clone(),
|
||||
@@ -340,7 +345,7 @@ async fn sandbox_distinguishes_command_and_policy_cwds() {
|
||||
canonical_allowed_path.to_string_lossy().into_owned(),
|
||||
],
|
||||
command_root,
|
||||
&policy,
|
||||
&permission_profile,
|
||||
&canonical_sandbox_root,
|
||||
StdioPolicy::Inherit,
|
||||
sandbox_env,
|
||||
@@ -375,12 +380,12 @@ async fn sandbox_blocks_first_time_dot_codex_creation() {
|
||||
create_dir_all(&repo_root).await.expect("mkdir repo");
|
||||
let dot_codex = repo_root.join(".codex");
|
||||
let config_toml = dot_codex.join("config.toml");
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
let permission_profile = PermissionProfile::workspace_write_with(
|
||||
&[],
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
/*exclude_tmpdir_env_var*/ true,
|
||||
/*exclude_slash_tmp*/ true,
|
||||
);
|
||||
|
||||
let mut child = spawn_command_under_sandbox(
|
||||
vec![
|
||||
@@ -390,7 +395,7 @@ async fn sandbox_blocks_first_time_dot_codex_creation() {
|
||||
.to_string(),
|
||||
],
|
||||
repo_root.clone(),
|
||||
&policy,
|
||||
&permission_profile,
|
||||
&repo_root,
|
||||
StdioPolicy::RedirectForShellTool,
|
||||
sandbox_env,
|
||||
@@ -507,7 +512,7 @@ fn unix_sock_body() {
|
||||
async fn allow_unix_socketpair_recvfrom() {
|
||||
run_code_under_sandbox(
|
||||
"allow_unix_socketpair_recvfrom",
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
&PermissionProfile::read_only(),
|
||||
|| async { unix_sock_body() },
|
||||
)
|
||||
.await
|
||||
@@ -519,7 +524,7 @@ const IN_SANDBOX_ENV_VAR: &str = "IN_SANDBOX";
|
||||
#[expect(clippy::expect_used)]
|
||||
pub async fn run_code_under_sandbox<F, Fut>(
|
||||
test_selector: &str,
|
||||
policy: &SandboxPolicy,
|
||||
permission_profile: &PermissionProfile,
|
||||
child_body: F,
|
||||
) -> io::Result<Option<ExitStatus>>
|
||||
where
|
||||
@@ -544,7 +549,7 @@ where
|
||||
let mut child = spawn_command_under_sandbox(
|
||||
cmds,
|
||||
command_cwd,
|
||||
policy,
|
||||
permission_profile,
|
||||
&sandbox_cwd,
|
||||
stdio_policy,
|
||||
HashMap::from([("IN_SANDBOX".into(), "1".into())]),
|
||||
|
||||
Reference in New Issue
Block a user