Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions codex-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions codex-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ members = [
"debug-client",
"apply-patch",
"arg0",
"feedback",
"features",
"codex-backend-openapi-models",
"cloud-requirements",
"cloud-tasks",
Expand All @@ -29,6 +27,9 @@ members = [
"exec-server",
"execpolicy",
"execpolicy-legacy",
"feedback",
"features",
"fs-ops",
"keyring-store",
"file-search",
"linux-sandbox",
Expand Down Expand Up @@ -111,9 +112,10 @@ codex-exec = { path = "exec" }
codex-exec-server = { path = "exec-server" }
codex-execpolicy = { path = "execpolicy" }
codex-experimental-api-macros = { path = "codex-experimental-api-macros" }
codex-feedback = { path = "feedback" }
codex-features = { path = "features" }
codex-feedback = { path = "feedback" }
codex-file-search = { path = "file-search" }
codex-fs-ops = { path = "fs-ops" }
codex-git = { path = "utils/git" }
codex-hooks = { path = "hooks" }
codex-keyring-store = { path = "keyring-store" }
Expand Down
1 change: 1 addition & 0 deletions codex-rs/arg0/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ workspace = true
[dependencies]
anyhow = { workspace = true }
codex-apply-patch = { workspace = true }
codex-fs-ops = { workspace = true }
codex-linux-sandbox = { workspace = true }
codex-shell-escalation = { workspace = true }
codex-utils-home-dir = { workspace = true }
Expand Down
7 changes: 7 additions & 0 deletions codex-rs/arg0/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::path::Path;
use std::path::PathBuf;

use codex_apply_patch::CODEX_CORE_APPLY_PATCH_ARG1;
use codex_fs_ops::CODEX_CORE_FS_OPS_ARG1;
use codex_utils_home_dir::find_codex_home;
#[cfg(unix)]
use std::os::unix::fs::symlink;
Expand Down Expand Up @@ -105,6 +106,12 @@ pub fn arg0_dispatch() -> Option<Arg0PathEntryGuard> {
};
std::process::exit(exit_code);
}
if argv1 == CODEX_CORE_FS_OPS_ARG1 {
let mut stdin = std::io::stdin();
let mut stdout = std::io::stdout();
let mut stderr = std::io::stderr();
codex_fs_ops::run_from_args_and_exit(args, &mut stdin, &mut stdout, &mut stderr);
}

// This modifies the environment, which is not thread-safe, so do this
// before creating any threads/the Tokio runtime.
Expand Down
1 change: 1 addition & 0 deletions codex-rs/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ codex-login = { workspace = true }
codex-shell-command = { workspace = true }
codex-skills = { workspace = true }
codex-execpolicy = { workspace = true }
codex-fs-ops = { workspace = true }
codex-file-search = { workspace = true }
codex-git = { workspace = true }
codex-hooks = { workspace = true }
Expand Down
150 changes: 112 additions & 38 deletions codex-rs/core/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,62 @@ pub(crate) async fn execute_exec_request(
stdout_stream: Option<StdoutStream>,
after_spawn: Option<Box<dyn FnOnce() + Send>>,
) -> Result<ExecToolCallOutput> {
let PreparedExecRequest {
params,
sandbox,
file_system_sandbox_policy,
network_sandbox_policy,
} = prepare_exec_request(exec_request);
let start = Instant::now();
let raw_output_result = exec(
params,
sandbox,
sandbox_policy,
&file_system_sandbox_policy,
network_sandbox_policy,
stdout_stream,
after_spawn,
)
.await;
let duration = start.elapsed();
Ok(normalize_exec_result(raw_output_result, sandbox, duration)?.to_utf8_lossy_output())
}

pub(crate) async fn execute_exec_request_raw_output(
exec_request: ExecRequest,
sandbox_policy: &SandboxPolicy,
stdout_stream: Option<StdoutStream>,
after_spawn: Option<Box<dyn FnOnce() + Send>>,
) -> Result<ExecToolCallRawOutput> {
let PreparedExecRequest {
params,
sandbox,
file_system_sandbox_policy,
network_sandbox_policy,
} = prepare_exec_request(exec_request);
let start = Instant::now();
let raw_output_result = exec(
params,
sandbox,
sandbox_policy,
&file_system_sandbox_policy,
network_sandbox_policy,
stdout_stream,
after_spawn,
)
.await;
let duration = start.elapsed();
normalize_exec_result(raw_output_result, sandbox, duration)
}

struct PreparedExecRequest {
params: ExecParams,
sandbox: SandboxType,
file_system_sandbox_policy: FileSystemSandboxPolicy,
network_sandbox_policy: NetworkSandboxPolicy,
}

fn prepare_exec_request(exec_request: ExecRequest) -> PreparedExecRequest {
let ExecRequest {
command,
cwd,
Expand All @@ -338,33 +394,24 @@ pub(crate) async fn execute_exec_request(
} = exec_request;
let _ = _sandbox_policy_from_env;

let params = ExecParams {
command,
cwd,
expiration,
capture_policy,
env,
network: network.clone(),
sandbox_permissions,
windows_sandbox_level,
windows_sandbox_private_desktop,
justification,
arg0,
};

let start = Instant::now();
let raw_output_result = exec(
params,
PreparedExecRequest {
params: ExecParams {
command,
cwd,
expiration,
capture_policy,
env,
network,
sandbox_permissions,
windows_sandbox_level,
windows_sandbox_private_desktop,
justification,
arg0,
},
sandbox,
sandbox_policy,
&file_system_sandbox_policy,
network_sandbox_policy,
stdout_stream,
after_spawn,
)
.await;
let duration = start.elapsed();
finalize_exec_result(raw_output_result, sandbox, duration)
file_system_sandbox_policy,
}
}

#[cfg(target_os = "windows")]
Expand Down Expand Up @@ -558,19 +605,25 @@ async fn exec_windows_sandbox(
})
}

fn finalize_exec_result(
fn normalize_exec_result(
raw_output_result: std::result::Result<RawExecToolCallOutput, CodexErr>,
sandbox_type: SandboxType,
duration: Duration,
) -> Result<ExecToolCallOutput> {
) -> Result<ExecToolCallRawOutput> {
match raw_output_result {
Ok(raw_output) => {
#[allow(unused_mut)]
let mut timed_out = raw_output.timed_out;
let RawExecToolCallOutput {
exit_status,
stdout,
stderr,
aggregated_output,
#[cfg_attr(target_os = "windows", allow(unused_mut))]
mut timed_out,
} = raw_output;

#[cfg(target_family = "unix")]
{
if let Some(signal) = raw_output.exit_status.signal() {
if let Some(signal) = exit_status.signal() {
if signal == TIMEOUT_CODE {
timed_out = true;
} else {
Expand All @@ -579,15 +632,12 @@ fn finalize_exec_result(
}
}

let mut exit_code = raw_output.exit_status.code().unwrap_or(-1);
let mut exit_code = exit_status.code().unwrap_or(-1);
if timed_out {
exit_code = EXEC_TIMEOUT_EXIT_CODE;
}

let stdout = raw_output.stdout.from_utf8_lossy();
let stderr = raw_output.stderr.from_utf8_lossy();
let aggregated_output = raw_output.aggregated_output.from_utf8_lossy();
let exec_output = ExecToolCallOutput {
let exec_output = ExecToolCallRawOutput {
exit_code,
stdout,
stderr,
Expand All @@ -598,13 +648,14 @@ fn finalize_exec_result(

if timed_out {
return Err(CodexErr::Sandbox(SandboxErr::Timeout {
output: Box::new(exec_output),
output: Box::new(exec_output.to_utf8_lossy_output()),
}));
}

if is_likely_sandbox_denied(sandbox_type, &exec_output) {
let string_output = exec_output.to_utf8_lossy_output();
if is_likely_sandbox_denied(sandbox_type, &string_output) {
return Err(CodexErr::Sandbox(SandboxErr::Denied {
output: Box::new(exec_output),
output: Box::new(string_output),
network_policy_decision: None,
}));
}
Expand Down Expand Up @@ -796,6 +847,16 @@ pub struct ExecToolCallOutput {
pub timed_out: bool,
}

#[derive(Clone, Debug)]
pub(crate) struct ExecToolCallRawOutput {
pub exit_code: i32,
pub stdout: StreamOutput<Vec<u8>>,
pub stderr: StreamOutput<Vec<u8>>,
pub aggregated_output: StreamOutput<Vec<u8>>,
pub duration: Duration,
pub timed_out: bool,
}

impl Default for ExecToolCallOutput {
fn default() -> Self {
Self {
Expand All @@ -809,6 +870,19 @@ impl Default for ExecToolCallOutput {
}
}

impl ExecToolCallRawOutput {
fn to_utf8_lossy_output(&self) -> ExecToolCallOutput {
ExecToolCallOutput {
exit_code: self.exit_code,
stdout: self.stdout.from_utf8_lossy(),
stderr: self.stderr.from_utf8_lossy(),
aggregated_output: self.aggregated_output.from_utf8_lossy(),
duration: self.duration,
timed_out: self.timed_out,
}
}
}

#[cfg_attr(not(target_os = "windows"), allow(unused_variables))]
async fn exec(
params: ExecParams,
Expand Down
1 change: 1 addition & 0 deletions codex-rs/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ pub mod default_client {
pub mod project_doc;
mod rollout;
pub(crate) mod safety;
mod sandboxed_fs;
pub mod seatbelt;
pub mod shell;
pub mod shell_snapshot;
Expand Down
Loading
Loading