log sandbox commands to $CODEX_HOME instead of cwd (#6171)

Logging commands in the Windows Sandbox is temporary, but while we are
doing it, let's always write to CODEX_HOME instead of dirtying the cwd.
This commit is contained in:
iceweasel-oai
2025-11-03 13:12:33 -08:00
committed by GitHub
parent 6ee7fbcfff
commit 07b7d28937
5 changed files with 48 additions and 23 deletions

View File

@@ -124,6 +124,7 @@ async fn run_command_under_sandbox(
let cwd_clone = cwd.clone(); let cwd_clone = cwd.clone();
let env_map = env.clone(); let env_map = env.clone();
let command_vec = command.clone(); let command_vec = command.clone();
let base_dir = config.codex_home.clone();
let res = tokio::task::spawn_blocking(move || { let res = tokio::task::spawn_blocking(move || {
run_windows_sandbox_capture( run_windows_sandbox_capture(
policy_str, policy_str,
@@ -132,6 +133,7 @@ async fn run_command_under_sandbox(
&cwd_clone, &cwd_clone,
env_map, env_map,
None, None,
Some(base_dir.as_path()),
) )
}) })
.await; .await;

View File

@@ -171,6 +171,7 @@ async fn exec_windows_sandbox(
params: ExecParams, params: ExecParams,
sandbox_policy: &SandboxPolicy, sandbox_policy: &SandboxPolicy,
) -> Result<RawExecToolCallOutput> { ) -> Result<RawExecToolCallOutput> {
use crate::config::find_codex_home;
use codex_windows_sandbox::run_windows_sandbox_capture; use codex_windows_sandbox::run_windows_sandbox_capture;
let ExecParams { let ExecParams {
@@ -188,8 +189,17 @@ async fn exec_windows_sandbox(
}; };
let sandbox_cwd = cwd.clone(); let sandbox_cwd = cwd.clone();
let logs_base_dir = find_codex_home().ok();
let spawn_res = tokio::task::spawn_blocking(move || { let spawn_res = tokio::task::spawn_blocking(move || {
run_windows_sandbox_capture(policy_str, &sandbox_cwd, command, &cwd, env, timeout_ms) run_windows_sandbox_capture(
policy_str,
&sandbox_cwd,
command,
&cwd,
env,
timeout_ms,
logs_base_dir.as_deref(),
)
}) })
.await; .await;

View File

@@ -182,6 +182,7 @@ mod windows_impl {
cwd: &Path, cwd: &Path,
mut env_map: HashMap<String, String>, mut env_map: HashMap<String, String>,
timeout_ms: Option<u64>, timeout_ms: Option<u64>,
logs_base_dir: Option<&Path>,
) -> Result<CaptureResult> { ) -> Result<CaptureResult> {
let policy = SandboxPolicy::parse(policy_json_or_preset)?; let policy = SandboxPolicy::parse(policy_json_or_preset)?;
normalize_null_device_env(&mut env_map); normalize_null_device_env(&mut env_map);
@@ -191,7 +192,7 @@ mod windows_impl {
let current_dir = cwd.to_path_buf(); let current_dir = cwd.to_path_buf();
// for now, don't fail if we detect world-writable directories // for now, don't fail if we detect world-writable directories
// audit::audit_everyone_writable(&current_dir, &env_map)?; // audit::audit_everyone_writable(&current_dir, &env_map)?;
log_start(&command); log_start(&command, logs_base_dir);
let (h_token, psid_to_use): (HANDLE, *mut c_void) = unsafe { let (h_token, psid_to_use): (HANDLE, *mut c_void) = unsafe {
match &policy.0 { match &policy.0 {
SandboxMode::ReadOnly => { SandboxMode::ReadOnly => {
@@ -295,7 +296,7 @@ mod windows_impl {
env_block.len(), env_block.len(),
si.dwFlags, si.dwFlags,
); );
debug_log(&dbg); debug_log(&dbg, logs_base_dir);
unsafe { unsafe {
CloseHandle(in_r); CloseHandle(in_r);
CloseHandle(in_w); CloseHandle(in_w);
@@ -395,9 +396,9 @@ mod windows_impl {
}; };
if exit_code == 0 { if exit_code == 0 {
log_success(&command); log_success(&command, logs_base_dir);
} else { } else {
log_failure(&command, &format!("exit code {}", exit_code)); log_failure(&command, &format!("exit code {}", exit_code), logs_base_dir);
} }
if !persist_aces { if !persist_aces {
@@ -446,6 +447,7 @@ mod stub {
_cwd: &Path, _cwd: &Path,
_env_map: HashMap<String, String>, _env_map: HashMap<String, String>,
_timeout_ms: Option<u64>, _timeout_ms: Option<u64>,
_logs_base_dir: Option<&Path>,
) -> Result<CaptureResult> { ) -> Result<CaptureResult> {
bail!("Windows sandbox is only available on Windows") bail!("Windows sandbox is only available on Windows")
} }

View File

@@ -1,5 +1,7 @@
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::Write; use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
const LOG_COMMAND_PREVIEW_LIMIT: usize = 200; const LOG_COMMAND_PREVIEW_LIMIT: usize = 200;
pub const LOG_FILE_NAME: &str = "sandbox_commands.rust.log"; pub const LOG_FILE_NAME: &str = "sandbox_commands.rust.log";
@@ -13,35 +15,43 @@ fn preview(command: &[String]) -> String {
} }
} }
fn append_line(line: &str) { fn log_file_path(base_dir: &Path) -> Option<PathBuf> {
if let Ok(mut f) = OpenOptions::new() if base_dir.is_dir() {
.create(true) Some(base_dir.join(LOG_FILE_NAME))
.append(true) } else {
.open(LOG_FILE_NAME) None
{
let _ = writeln!(f, "{}", line);
} }
} }
pub fn log_start(command: &[String]) { fn append_line(line: &str, base_dir: Option<&Path>) {
let p = preview(command); if let Some(dir) = base_dir {
append_line(&format!("START: {}", p)); if let Some(path) = log_file_path(dir) {
if let Ok(mut f) = OpenOptions::new().create(true).append(true).open(path) {
let _ = writeln!(f, "{}", line);
}
}
}
} }
pub fn log_success(command: &[String]) { pub fn log_start(command: &[String], base_dir: Option<&Path>) {
let p = preview(command); let p = preview(command);
append_line(&format!("SUCCESS: {}", p)); append_line(&format!("START: {p}"), base_dir);
} }
pub fn log_failure(command: &[String], detail: &str) { pub fn log_success(command: &[String], base_dir: Option<&Path>) {
let p = preview(command); let p = preview(command);
append_line(&format!("FAILURE: {} ({})", p, detail)); append_line(&format!("SUCCESS: {p}"), base_dir);
}
pub fn log_failure(command: &[String], detail: &str, base_dir: Option<&Path>) {
let p = preview(command);
append_line(&format!("FAILURE: {p} ({detail})"), base_dir);
} }
// Debug logging helper. Emits only when SBX_DEBUG=1 to avoid noisy logs. // Debug logging helper. Emits only when SBX_DEBUG=1 to avoid noisy logs.
pub fn debug_log(msg: &str) { pub fn debug_log(msg: &str, base_dir: Option<&Path>) {
if std::env::var("SBX_DEBUG").ok().as_deref() == Some("1") { if std::env::var("SBX_DEBUG").ok().as_deref() == Some("1") {
append_line(&format!("DEBUG: {}", msg)); append_line(&format!("DEBUG: {msg}"), base_dir);
eprintln!("{}", msg); eprintln!("{msg}");
} }
} }

View File

@@ -101,6 +101,7 @@ pub unsafe fn create_process_as_user(
argv: &[String], argv: &[String],
cwd: &Path, cwd: &Path,
env_map: &HashMap<String, String>, env_map: &HashMap<String, String>,
logs_base_dir: Option<&Path>,
) -> Result<(PROCESS_INFORMATION, STARTUPINFOW)> { ) -> Result<(PROCESS_INFORMATION, STARTUPINFOW)> {
let cmdline_str = argv let cmdline_str = argv
.iter() .iter()
@@ -142,7 +143,7 @@ pub unsafe fn create_process_as_user(
env_block.len(), env_block.len(),
si.dwFlags, si.dwFlags,
); );
logging::debug_log(&msg); logging::debug_log(&msg, logs_base_dir);
return Err(anyhow!("CreateProcessAsUserW failed: {}", err)); return Err(anyhow!("CreateProcessAsUserW failed: {}", err));
} }
Ok((pi, si)) Ok((pi, si))