mirror of
https://github.com/openai/codex.git
synced 2026-05-21 11:42:55 +00:00
Thread Windows metadata targets through sessions
This commit is contained in:
@@ -372,6 +372,7 @@ async fn run_command_under_windows_session(
|
||||
None,
|
||||
/*tty*/ false,
|
||||
/*stdin_open*/ true,
|
||||
&[],
|
||||
config.permissions.windows_sandbox_private_desktop,
|
||||
)
|
||||
.await
|
||||
@@ -386,6 +387,7 @@ async fn run_command_under_windows_session(
|
||||
None,
|
||||
/*tty*/ false,
|
||||
/*stdin_open*/ true,
|
||||
&[],
|
||||
config.permissions.windows_sandbox_private_desktop,
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -407,39 +407,18 @@ pub fn build_exec_request(
|
||||
ExecRequest::from_sandbox_exec_request(request, options, windows_sandbox_policy_cwd)
|
||||
})
|
||||
.map_err(CodexErr::from)?;
|
||||
let use_windows_elevated_backend = windows_sandbox_uses_elevated_backend(
|
||||
exec_req.windows_sandbox_level,
|
||||
exec_req.network.is_some(),
|
||||
);
|
||||
let sandbox_policy = exec_req.compatibility_sandbox_policy();
|
||||
exec_req.windows_sandbox_filesystem_overrides = if use_windows_elevated_backend {
|
||||
resolve_windows_elevated_filesystem_overrides(
|
||||
exec_req.sandbox,
|
||||
&sandbox_policy,
|
||||
&exec_req.file_system_sandbox_policy,
|
||||
exec_req.network_sandbox_policy,
|
||||
sandbox_cwd,
|
||||
use_windows_elevated_backend,
|
||||
)
|
||||
} else {
|
||||
resolve_windows_restricted_token_filesystem_overrides(
|
||||
exec_req.sandbox,
|
||||
&sandbox_policy,
|
||||
&exec_req.file_system_sandbox_policy,
|
||||
exec_req.network_sandbox_policy,
|
||||
sandbox_cwd,
|
||||
exec_req.windows_sandbox_level,
|
||||
)
|
||||
}
|
||||
.map_err(CodexErr::UnsupportedOperation)?;
|
||||
ensure_windows_sandbox_filesystem_overrides(&mut exec_req)
|
||||
.map_err(CodexErr::UnsupportedOperation)?;
|
||||
Ok(exec_req)
|
||||
}
|
||||
|
||||
pub(crate) async fn execute_exec_request(
|
||||
exec_request: ExecRequest,
|
||||
mut exec_request: ExecRequest,
|
||||
stdout_stream: Option<StdoutStream>,
|
||||
after_spawn: Option<Box<dyn FnOnce() + Send>>,
|
||||
) -> Result<ExecToolCallOutput> {
|
||||
ensure_windows_sandbox_filesystem_overrides(&mut exec_request)
|
||||
.map_err(CodexErr::UnsupportedOperation)?;
|
||||
let sandbox_policy = exec_request.compatibility_sandbox_policy();
|
||||
let ExecRequest {
|
||||
command,
|
||||
@@ -489,6 +468,36 @@ pub(crate) async fn execute_exec_request(
|
||||
finalize_exec_result(raw_output_result, sandbox, duration)
|
||||
}
|
||||
|
||||
pub(crate) fn ensure_windows_sandbox_filesystem_overrides(
|
||||
exec_req: &mut ExecRequest,
|
||||
) -> std::result::Result<(), String> {
|
||||
let use_windows_elevated_backend = windows_sandbox_uses_elevated_backend(
|
||||
exec_req.windows_sandbox_level,
|
||||
exec_req.network.is_some(),
|
||||
);
|
||||
let sandbox_policy = exec_req.compatibility_sandbox_policy();
|
||||
exec_req.windows_sandbox_filesystem_overrides = if use_windows_elevated_backend {
|
||||
resolve_windows_elevated_filesystem_overrides(
|
||||
exec_req.sandbox,
|
||||
&sandbox_policy,
|
||||
&exec_req.file_system_sandbox_policy,
|
||||
exec_req.network_sandbox_policy,
|
||||
&exec_req.windows_sandbox_policy_cwd,
|
||||
use_windows_elevated_backend,
|
||||
)
|
||||
} else {
|
||||
resolve_windows_restricted_token_filesystem_overrides(
|
||||
exec_req.sandbox,
|
||||
&sandbox_policy,
|
||||
&exec_req.file_system_sandbox_policy,
|
||||
exec_req.network_sandbox_policy,
|
||||
&exec_req.windows_sandbox_policy_cwd,
|
||||
exec_req.windows_sandbox_level,
|
||||
)
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_raw_output_result(
|
||||
params: ExecParams,
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
|
||||
@@ -41,7 +41,7 @@ pub(crate) struct ExecServerEnvConfig {
|
||||
pub(crate) local_policy_env: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ExecRequest {
|
||||
pub command: Vec<String>,
|
||||
pub cwd: AbsolutePathBuf,
|
||||
|
||||
@@ -11,6 +11,8 @@ use tokio::time::Duration;
|
||||
use tokio::time::Instant;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use crate::exec::WindowsProtectedMetadataMode;
|
||||
use crate::exec_env::CODEX_THREAD_ID_ENV_VAR;
|
||||
use crate::exec_env::create_env;
|
||||
use crate::exec_policy::ExecApprovalRequest;
|
||||
@@ -163,6 +165,45 @@ fn exec_server_params_for_request(
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_exec_request_for_open_session(
|
||||
request: &ExecRequest,
|
||||
) -> Result<ExecRequest, UnifiedExecError> {
|
||||
let mut request = request.clone();
|
||||
crate::exec::ensure_windows_sandbox_filesystem_overrides(&mut request)
|
||||
.map_err(UnifiedExecError::create_process)?;
|
||||
Ok(request)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn protected_metadata_targets_for_windows_session(
|
||||
request: &ExecRequest,
|
||||
) -> Vec<codex_windows_sandbox::ProtectedMetadataTarget> {
|
||||
request
|
||||
.windows_sandbox_filesystem_overrides
|
||||
.as_ref()
|
||||
.map(|overrides| {
|
||||
overrides
|
||||
.protected_metadata_targets
|
||||
.iter()
|
||||
.map(|target| {
|
||||
let mode = match target.mode {
|
||||
WindowsProtectedMetadataMode::ExistingDeny => {
|
||||
codex_windows_sandbox::ProtectedMetadataMode::ExistingDeny
|
||||
}
|
||||
WindowsProtectedMetadataMode::MissingCreationMonitor => {
|
||||
codex_windows_sandbox::ProtectedMetadataMode::MissingCreationMonitor
|
||||
}
|
||||
};
|
||||
codex_windows_sandbox::ProtectedMetadataTarget {
|
||||
path: target.path.to_path_buf(),
|
||||
mode,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Borrowed process state prepared for a `write_stdin` or poll operation.
|
||||
struct PreparedProcessHandles {
|
||||
process: Arc<UnifiedExecProcess>,
|
||||
@@ -873,6 +914,7 @@ impl UnifiedExecProcessManager {
|
||||
mut spawn_lifecycle: SpawnLifecycleHandle,
|
||||
environment: &codex_exec_server::Environment,
|
||||
) -> Result<UnifiedExecProcess, UnifiedExecError> {
|
||||
let request = prepare_exec_request_for_open_session(request)?;
|
||||
let inherited_fds = spawn_lifecycle.inherited_fds();
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -888,6 +930,8 @@ impl UnifiedExecProcessManager {
|
||||
"windows sandbox: failed to resolve codex_home: {err}"
|
||||
))
|
||||
})?;
|
||||
let protected_metadata_targets =
|
||||
protected_metadata_targets_for_windows_session(&request);
|
||||
let spawned = match request.windows_sandbox_level {
|
||||
codex_protocol::config_types::WindowsSandboxLevel::Elevated => {
|
||||
codex_windows_sandbox::spawn_windows_sandbox_session_elevated(
|
||||
@@ -900,6 +944,7 @@ impl UnifiedExecProcessManager {
|
||||
None,
|
||||
tty,
|
||||
tty,
|
||||
&protected_metadata_targets,
|
||||
request.windows_sandbox_private_desktop,
|
||||
)
|
||||
.await
|
||||
@@ -916,6 +961,7 @@ impl UnifiedExecProcessManager {
|
||||
None,
|
||||
tty,
|
||||
tty,
|
||||
&protected_metadata_targets,
|
||||
request.windows_sandbox_private_desktop,
|
||||
)
|
||||
.await
|
||||
@@ -938,7 +984,7 @@ impl UnifiedExecProcessManager {
|
||||
|
||||
let started = environment
|
||||
.get_exec_backend()
|
||||
.start(exec_server_params_for_request(process_id, request, tty))
|
||||
.start(exec_server_params_for_request(process_id, &request, tty))
|
||||
.await
|
||||
.map_err(|err| UnifiedExecError::create_process(err.to_string()))?;
|
||||
spawn_lifecycle.after_spawn();
|
||||
|
||||
@@ -135,6 +135,68 @@ fn exec_server_process_id_matches_unified_exec_process_id() {
|
||||
assert_eq!(exec_server_process_id(/*process_id*/ 4321), "4321");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn open_session_prepares_windows_metadata_overrides_for_unified_exec() {
|
||||
let temp_dir = tempfile::TempDir::new().expect("tempdir");
|
||||
let cwd: codex_utils_absolute_path::AbsolutePathBuf = dunce::canonicalize(temp_dir.path())
|
||||
.expect("canonical temp dir")
|
||||
.try_into()
|
||||
.expect("absolute temp dir");
|
||||
let permission_profile = codex_protocol::models::PermissionProfile::workspace_write_with(
|
||||
&[],
|
||||
codex_protocol::permissions::NetworkSandboxPolicy::Restricted,
|
||||
/*exclude_tmpdir_env_var*/ true,
|
||||
/*exclude_slash_tmp*/ true,
|
||||
);
|
||||
let (file_system_sandbox_policy, network_sandbox_policy) =
|
||||
permission_profile.to_runtime_permissions();
|
||||
let request = ExecRequest {
|
||||
command: vec![
|
||||
"cmd.exe".to_string(),
|
||||
"/c".to_string(),
|
||||
"echo ok".to_string(),
|
||||
],
|
||||
cwd: cwd.clone(),
|
||||
env: HashMap::new(),
|
||||
exec_server_env_config: None,
|
||||
network: None,
|
||||
expiration: crate::exec::ExecExpiration::DefaultTimeout,
|
||||
capture_policy: crate::exec::ExecCapturePolicy::ShellTool,
|
||||
sandbox: codex_sandboxing::SandboxType::WindowsRestrictedToken,
|
||||
windows_sandbox_policy_cwd: cwd.clone(),
|
||||
windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel::RestrictedToken,
|
||||
windows_sandbox_private_desktop: false,
|
||||
permission_profile,
|
||||
file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
windows_sandbox_filesystem_overrides: None,
|
||||
arg0: None,
|
||||
};
|
||||
|
||||
let prepared = prepare_exec_request_for_open_session(&request).expect("prepare request");
|
||||
let overrides = prepared
|
||||
.windows_sandbox_filesystem_overrides
|
||||
.expect("metadata overrides");
|
||||
|
||||
assert_eq!(
|
||||
overrides.protected_metadata_targets,
|
||||
vec![
|
||||
crate::exec::WindowsProtectedMetadataTarget {
|
||||
path: cwd.join(".agents"),
|
||||
mode: crate::exec::WindowsProtectedMetadataMode::MissingCreationMonitor,
|
||||
},
|
||||
crate::exec::WindowsProtectedMetadataTarget {
|
||||
path: cwd.join(".codex"),
|
||||
mode: crate::exec::WindowsProtectedMetadataMode::MissingCreationMonitor,
|
||||
},
|
||||
crate::exec::WindowsProtectedMetadataTarget {
|
||||
path: cwd.join(".git"),
|
||||
mode: crate::exec::WindowsProtectedMetadataMode::MissingCreationMonitor,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn network_denial_fallback_message_names_sandbox_network_proxy() {
|
||||
let message = network_denial_message_for_session(/*session*/ None, /*deferred*/ None).await;
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::ipc_framed::FramedMessage;
|
||||
use crate::ipc_framed::Message;
|
||||
use crate::ipc_framed::SpawnRequest;
|
||||
use crate::runner_client::spawn_runner_transport;
|
||||
use crate::setup::ProtectedMetadataTarget;
|
||||
use crate::spawn_prep::prepare_elevated_spawn_context;
|
||||
use anyhow::Result;
|
||||
use codex_utils_pty::ProcessDriver;
|
||||
@@ -29,6 +30,7 @@ pub(crate) async fn spawn_windows_sandbox_session_elevated(
|
||||
timeout_ms: Option<u64>,
|
||||
tty: bool,
|
||||
stdin_open: bool,
|
||||
protected_metadata_targets: &[ProtectedMetadataTarget],
|
||||
use_private_desktop: bool,
|
||||
) -> Result<SpawnedProcess> {
|
||||
let elevated = prepare_elevated_spawn_context(
|
||||
@@ -38,7 +40,7 @@ pub(crate) async fn spawn_windows_sandbox_session_elevated(
|
||||
cwd,
|
||||
&mut env_map,
|
||||
&command,
|
||||
&[],
|
||||
protected_metadata_targets,
|
||||
)?;
|
||||
|
||||
let spawn_request = SpawnRequest {
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::process::StderrMode;
|
||||
use crate::process::StdinMode;
|
||||
use crate::process::read_handle_loop;
|
||||
use crate::process::spawn_process_with_pipes;
|
||||
use crate::setup::ProtectedMetadataTarget;
|
||||
use crate::spawn_prep::LocalSid;
|
||||
use crate::spawn_prep::allow_null_device_for_workspace_write;
|
||||
use crate::spawn_prep::apply_legacy_session_acl_rules;
|
||||
@@ -289,6 +290,7 @@ pub(crate) async fn spawn_windows_sandbox_session_legacy(
|
||||
timeout_ms: Option<u64>,
|
||||
tty: bool,
|
||||
stdin_open: bool,
|
||||
_protected_metadata_targets: &[ProtectedMetadataTarget],
|
||||
use_private_desktop: bool,
|
||||
) -> Result<SpawnedProcess> {
|
||||
let common = prepare_legacy_spawn_context(
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
mod backends;
|
||||
|
||||
use crate::setup::ProtectedMetadataTarget;
|
||||
use anyhow::Result;
|
||||
use codex_utils_pty::SpawnedProcess;
|
||||
use std::collections::HashMap;
|
||||
@@ -25,6 +26,7 @@ pub async fn spawn_windows_sandbox_session_legacy(
|
||||
timeout_ms: Option<u64>,
|
||||
tty: bool,
|
||||
stdin_open: bool,
|
||||
protected_metadata_targets: &[ProtectedMetadataTarget],
|
||||
use_private_desktop: bool,
|
||||
) -> Result<SpawnedProcess> {
|
||||
backends::legacy::spawn_windows_sandbox_session_legacy(
|
||||
@@ -37,6 +39,7 @@ pub async fn spawn_windows_sandbox_session_legacy(
|
||||
timeout_ms,
|
||||
tty,
|
||||
stdin_open,
|
||||
protected_metadata_targets,
|
||||
use_private_desktop,
|
||||
)
|
||||
.await
|
||||
@@ -53,6 +56,7 @@ pub async fn spawn_windows_sandbox_session_elevated(
|
||||
timeout_ms: Option<u64>,
|
||||
tty: bool,
|
||||
stdin_open: bool,
|
||||
protected_metadata_targets: &[ProtectedMetadataTarget],
|
||||
use_private_desktop: bool,
|
||||
) -> Result<SpawnedProcess> {
|
||||
backends::elevated::spawn_windows_sandbox_session_elevated(
|
||||
@@ -65,6 +69,7 @@ pub async fn spawn_windows_sandbox_session_elevated(
|
||||
timeout_ms,
|
||||
tty,
|
||||
stdin_open,
|
||||
protected_metadata_targets,
|
||||
use_private_desktop,
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -162,6 +162,7 @@ fn legacy_non_tty_cmd_emits_output() {
|
||||
Some(5_000),
|
||||
/*tty*/ false,
|
||||
/*stdin_open*/ false,
|
||||
&[],
|
||||
/*use_private_desktop*/ true,
|
||||
)
|
||||
.await
|
||||
@@ -202,6 +203,7 @@ fn legacy_non_tty_powershell_emits_output() {
|
||||
Some(5_000),
|
||||
/*tty*/ false,
|
||||
/*stdin_open*/ false,
|
||||
&[],
|
||||
/*use_private_desktop*/ true,
|
||||
)
|
||||
.await
|
||||
@@ -426,6 +428,7 @@ fn legacy_tty_powershell_emits_output_and_accepts_input() {
|
||||
Some(10_000),
|
||||
/*tty*/ true,
|
||||
/*stdin_open*/ true,
|
||||
&[],
|
||||
/*use_private_desktop*/ true,
|
||||
)
|
||||
.await
|
||||
@@ -474,6 +477,7 @@ fn legacy_tty_cmd_emits_output_and_accepts_input() {
|
||||
Some(10_000),
|
||||
/*tty*/ true,
|
||||
/*stdin_open*/ true,
|
||||
&[],
|
||||
/*use_private_desktop*/ true,
|
||||
)
|
||||
.await
|
||||
@@ -525,6 +529,7 @@ fn legacy_tty_cmd_default_desktop_emits_output_and_accepts_input() {
|
||||
Some(10_000),
|
||||
/*tty*/ true,
|
||||
/*stdin_open*/ true,
|
||||
&[],
|
||||
/*use_private_desktop*/ false,
|
||||
)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user