diff --git a/codex-rs/utils/absolute-path/src/lib.rs b/codex-rs/utils/absolute-path/src/lib.rs index 1ba1c40cfb..9e047b3b0b 100644 --- a/codex-rs/utils/absolute-path/src/lib.rs +++ b/codex-rs/utils/absolute-path/src/lib.rs @@ -54,7 +54,14 @@ impl AbsolutePathBuf { pub fn from_absolute_path>(path: P) -> std::io::Result { let expanded = Self::maybe_expand_home_directory(path.as_ref()); - let absolute_path = expanded.absolutize()?; + let absolute_path = if expanded.is_absolute() { + // `path-absolutize` consults the process cwd in `absolutize()`, even + // for already-absolute paths. Keep absolute inputs independent from + // cwd so callers continue to work after the cwd disappears. + expanded.absolutize_from(Path::new("/"))? + } else { + expanded.absolutize()? + }; Ok(Self(absolute_path.into_owned())) } diff --git a/codex-rs/utils/absolute-path/tests/dead_cwd.rs b/codex-rs/utils/absolute-path/tests/dead_cwd.rs new file mode 100644 index 0000000000..2cd0b0a993 --- /dev/null +++ b/codex-rs/utils/absolute-path/tests/dead_cwd.rs @@ -0,0 +1,43 @@ +use codex_utils_absolute_path::AbsolutePathBuf; +use pretty_assertions::assert_eq; +use std::io; +use std::path::PathBuf; +use tempfile::tempdir; + +struct CurrentDirGuard { + previous: PathBuf, +} + +impl Drop for CurrentDirGuard { + fn drop(&mut self) { + std::env::set_current_dir(&self.previous).expect("restore cwd"); + } +} + +#[cfg(unix)] +#[test] +fn absolute_paths_still_resolve_when_current_dir_is_missing() -> io::Result<()> { + let target_root = tempdir()?; + let target_dir = target_root.path().join("target"); + std::fs::create_dir(&target_dir)?; + + let cwd_root = tempdir()?; + let cwd_dir = cwd_root.path().join("cwd"); + std::fs::create_dir(&cwd_dir)?; + + let _guard = CurrentDirGuard { + previous: std::env::current_dir()?, + }; + std::env::set_current_dir(&cwd_dir)?; + std::fs::remove_dir(&cwd_dir)?; + + assert_eq!( + std::env::current_dir().unwrap_err().kind(), + io::ErrorKind::NotFound + ); + + let target_path = target_dir.join("..").join("target"); + let resolved = AbsolutePathBuf::from_absolute_path(&target_path)?; + assert_eq!(resolved.as_path(), target_dir.as_path()); + Ok(()) +}