mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
fix: writable_roots doesn't recognize home directory symbol in non-windows OS (#9193)
Fixes: ``` [sandbox_workspace_write] writable_roots = ["~/code/"] ``` translates to ``` /Users/ccunningham/.codex/~/code ``` (i.e. the home dir symbol isn't recognized)
This commit is contained in:
1 parent
5ae6e70801
commit
2c3843728c
3 files changed
+70
-2
No files matched your search
Generated
+2
@@ -1888,7 +1888,9 @@ dependencies = [
|
|||||||
name = "codex-utils-absolute-path"
|
name = "codex-utils-absolute-path"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"dirs",
|
||||||
"path-absolutize",
|
"path-absolutize",
|
||||||
|
"pretty_assertions",
|
||||||
"schemars 0.8.22",
|
"schemars 0.8.22",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ license.workspace = true
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
dirs = { workspace = true }
|
||||||
path-absolutize = { workspace = true }
|
path-absolutize = { workspace = true }
|
||||||
schemars = { workspace = true }
|
schemars = { workspace = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
@@ -18,5 +19,6 @@ ts-rs = { workspace = true, features = [
|
|||||||
] }
|
] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
pretty_assertions = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
tempfile = { workspace = true }
|
tempfile = { workspace = true }
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use dirs::home_dir;
|
||||||
use path_absolutize::Absolutize;
|
use path_absolutize::Absolutize;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@@ -21,16 +22,35 @@ use ts_rs::TS;
|
|||||||
pub struct AbsolutePathBuf(PathBuf);
|
pub struct AbsolutePathBuf(PathBuf);
|
||||||
|
|
||||||
impl AbsolutePathBuf {
|
impl AbsolutePathBuf {
|
||||||
|
fn maybe_expand_home_directory(path: &Path) -> PathBuf {
|
||||||
|
let Some(path_str) = path.to_str() else {
|
||||||
|
return path.to_path_buf();
|
||||||
|
};
|
||||||
|
if cfg!(not(target_os = "windows"))
|
||||||
|
&& let Some(home) = home_dir()
|
||||||
|
{
|
||||||
|
if path_str == "~" {
|
||||||
|
return home;
|
||||||
|
}
|
||||||
|
if let Some(rest) = path_str.strip_prefix("~/") {
|
||||||
|
return home.join(rest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path.to_path_buf()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resolve_path_against_base<P: AsRef<Path>, B: AsRef<Path>>(
|
pub fn resolve_path_against_base<P: AsRef<Path>, B: AsRef<Path>>(
|
||||||
path: P,
|
path: P,
|
||||||
base_path: B,
|
base_path: B,
|
||||||
) -> std::io::Result<Self> {
|
) -> std::io::Result<Self> {
|
||||||
let absolute_path = path.as_ref().absolutize_from(base_path.as_ref())?;
|
let expanded = Self::maybe_expand_home_directory(path.as_ref());
|
||||||
|
let absolute_path = expanded.absolutize_from(base_path.as_ref())?;
|
||||||
Ok(Self(absolute_path.into_owned()))
|
Ok(Self(absolute_path.into_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_absolute_path<P: AsRef<Path>>(path: P) -> std::io::Result<Self> {
|
pub fn from_absolute_path<P: AsRef<Path>>(path: P) -> std::io::Result<Self> {
|
||||||
let absolute_path = path.as_ref().absolutize()?;
|
let expanded = Self::maybe_expand_home_directory(path.as_ref());
|
||||||
|
let absolute_path = expanded.absolutize()?;
|
||||||
Ok(Self(absolute_path.into_owned()))
|
Ok(Self(absolute_path.into_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +185,7 @@ impl<'de> Deserialize<'de> for AbsolutePathBuf {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -203,4 +224,47 @@ mod tests {
|
|||||||
base_dir.join(relative_path).as_path()
|
base_dir.join(relative_path).as_path()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
#[test]
|
||||||
|
fn home_directory_root_on_non_windows_is_expanded_in_deserialization() {
|
||||||
|
let Some(home) = home_dir() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let temp_dir = tempdir().expect("base dir");
|
||||||
|
let abs_path_buf = {
|
||||||
|
let _guard = AbsolutePathBufGuard::new(temp_dir.path());
|
||||||
|
serde_json::from_str::<AbsolutePathBuf>("\"~\"").expect("failed to deserialize")
|
||||||
|
};
|
||||||
|
assert_eq!(abs_path_buf.as_path(), home.as_path());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
#[test]
|
||||||
|
fn home_directory_subpath_on_non_windows_is_expanded_in_deserialization() {
|
||||||
|
let Some(home) = home_dir() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let temp_dir = tempdir().expect("base dir");
|
||||||
|
let abs_path_buf = {
|
||||||
|
let _guard = AbsolutePathBufGuard::new(temp_dir.path());
|
||||||
|
serde_json::from_str::<AbsolutePathBuf>("\"~/code\"").expect("failed to deserialize")
|
||||||
|
};
|
||||||
|
assert_eq!(abs_path_buf.as_path(), home.join("code").as_path());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
#[test]
|
||||||
|
fn home_directory_on_windows_is_not_expanded_in_deserialization() {
|
||||||
|
let temp_dir = tempdir().expect("base dir");
|
||||||
|
let base_dir = temp_dir.path();
|
||||||
|
let abs_path_buf = {
|
||||||
|
let _guard = AbsolutePathBufGuard::new(base_dir);
|
||||||
|
serde_json::from_str::<AbsolutePathBuf>("\"~/code\"").expect("failed to deserialize")
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
abs_path_buf.as_path(),
|
||||||
|
base_dir.join("~").join("code").as_path()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user