feat: make cwd a required field of Config so we stop assuming std::env::current_dir() in a session (#800)

In order to expose Codex via an MCP server, I realized that we should be
taking `cwd` as a parameter rather than assuming
`std::env::current_dir()` as the `cwd`. Specifically, the user may want
to start a session in a directory other than the one where the MCP
server has been started.

This PR makes `cwd: PathBuf` a required field of `Session` and threads
it all the way through, though I think there is still an issue with not
honoring `workdir` for `apply_patch`, which is something we also had to
fix in the TypeScript version: https://github.com/openai/codex/pull/556.

This also adds `-C`/`--cd` to change the cwd via the command line.

To test, I ran:

```
cargo run --bin codex -- exec -C /tmp 'show the output of ls'
```

and verified it showed the contents of my `/tmp` folder instead of
`$PWD`.
This commit is contained in:
Michael Bolin
2025-05-04 10:57:12 -07:00
committed by GitHub
parent 4b61fb8bab
commit 421e159888
18 changed files with 210 additions and 102 deletions

View File

@@ -22,6 +22,7 @@ pub fn assess_patch_safety(
changes: &HashMap<PathBuf, ApplyPatchFileChange>,
policy: AskForApproval,
writable_roots: &[PathBuf],
cwd: &Path,
) -> SafetyCheck {
if changes.is_empty() {
return SafetyCheck::Reject {
@@ -40,7 +41,7 @@ pub fn assess_patch_safety(
}
}
if is_write_patch_constrained_to_writable_paths(changes, writable_roots) {
if is_write_patch_constrained_to_writable_paths(changes, writable_roots, cwd) {
SafetyCheck::AutoApprove {
sandbox_type: SandboxType::None,
}
@@ -115,6 +116,7 @@ pub fn get_platform_sandbox() -> Option<SandboxType> {
fn is_write_patch_constrained_to_writable_paths(
changes: &HashMap<PathBuf, ApplyPatchFileChange>,
writable_roots: &[PathBuf],
cwd: &Path,
) -> bool {
// Earlyexit if there are no declared writable roots.
if writable_roots.is_empty() {
@@ -141,11 +143,6 @@ fn is_write_patch_constrained_to_writable_paths(
// and roots are converted to absolute, normalized forms before the
// prefix check.
let is_path_writable = |p: &PathBuf| {
let cwd = match std::env::current_dir() {
Ok(cwd) => cwd,
Err(_) => return false,
};
let abs = if p.is_absolute() {
p.clone()
} else {
@@ -217,19 +214,22 @@ mod tests {
assert!(is_write_patch_constrained_to_writable_paths(
&add_inside,
&[PathBuf::from(".")]
&[PathBuf::from(".")],
&cwd,
));
let add_outside_2 = make_add_change(parent.join("outside.txt"));
assert!(!is_write_patch_constrained_to_writable_paths(
&add_outside_2,
&[PathBuf::from(".")]
&[PathBuf::from(".")],
&cwd,
));
// With parent dir added as writable root, it should pass.
assert!(is_write_patch_constrained_to_writable_paths(
&add_outside,
&[PathBuf::from("..")]
&[PathBuf::from("..")],
&cwd,
))
}
}