codex: normalize apply_patch fs paths against symlinked ancestors

This commit is contained in:
starr-openai
2026-04-03 23:13:55 -07:00
parent 604b233fe5
commit 4b05e85f0d
2 changed files with 40 additions and 2 deletions

View File

@@ -163,12 +163,31 @@ impl ApplyPatchFileSystem for EnvironmentApplyPatchFileSystem {
}
fn absolute_path(path: &std::path::Path) -> std::result::Result<AbsolutePathBuf, ApplyPatchError> {
AbsolutePathBuf::from_absolute_path(path).map_err(|error| {
let path = AbsolutePathBuf::from_absolute_path(path).map_err(|error| {
ApplyPatchError::io_error(
format!("Expected absolute path for apply_patch: {}", path.display()),
io::Error::new(io::ErrorKind::InvalidInput, error.to_string()),
)
})
})?;
Ok(normalize_existing_ancestor_path(path))
}
fn normalize_existing_ancestor_path(path: AbsolutePathBuf) -> AbsolutePathBuf {
let raw_path = path.to_path_buf();
for ancestor in raw_path.ancestors() {
let Ok(canonical_ancestor) = ancestor.canonicalize() else {
continue;
};
let Ok(suffix) = raw_path.strip_prefix(ancestor) else {
continue;
};
if let Ok(normalized_path) =
AbsolutePathBuf::from_absolute_path(canonical_ancestor.join(suffix))
{
return normalized_path;
}
}
path
}
pub(crate) async fn apply_patch(

View File

@@ -31,6 +31,25 @@ fn convert_apply_patch_maps_add_variant() {
);
}
#[cfg(unix)]
#[test]
fn absolute_path_normalizes_existing_symlink_ancestor() {
use std::os::unix::fs::symlink;
let tmp = tempdir().expect("tempdir");
let real_root = tmp.path().join("real");
let link_root = tmp.path().join("link");
std::fs::create_dir_all(&real_root).expect("create real root");
symlink(&real_root, &link_root).expect("create symlink");
let path = link_root.join("nested").join("file.txt");
let got = absolute_path(path.as_path()).expect("normalize absolute path");
let expected = AbsolutePathBuf::from_absolute_path(real_root.join("nested/file.txt"))
.expect("expected normalized path");
assert_eq!(got, expected);
}
#[derive(Default)]
struct RecordingExecutorFileSystem {
raw_reads: Mutex<Vec<PathBuf>>,