mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Make AbsolutePathBuf joins infallible (#16981)
Having to check for errors every time join is called is painful and unnecessary.
This commit is contained in:
@@ -522,7 +522,7 @@ impl FileSystemSandboxPolicy {
|
||||
if suffix.as_os_str().is_empty() {
|
||||
return None;
|
||||
}
|
||||
root.join(suffix).ok()
|
||||
Some(root.join(suffix))
|
||||
})
|
||||
}
|
||||
} else {
|
||||
@@ -921,7 +921,7 @@ fn resolve_candidate_path(path: &Path, cwd: &Path) -> Option<AbsolutePathBuf> {
|
||||
if path.is_absolute() {
|
||||
AbsolutePathBuf::from_absolute_path(path).ok()
|
||||
} else {
|
||||
AbsolutePathBuf::resolve_path_against_base(path, cwd).ok()
|
||||
Some(AbsolutePathBuf::resolve_path_against_base(path, cwd))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1032,9 +1032,10 @@ fn resolve_file_system_special_path(
|
||||
FileSystemSpecialPath::ProjectRoots { subpath } => {
|
||||
let cwd = cwd?;
|
||||
match subpath.as_ref() {
|
||||
Some(subpath) => {
|
||||
AbsolutePathBuf::resolve_path_against_base(subpath, cwd.as_path()).ok()
|
||||
}
|
||||
Some(subpath) => Some(AbsolutePathBuf::resolve_path_against_base(
|
||||
subpath,
|
||||
cwd.as_path(),
|
||||
)),
|
||||
None => Some(cwd.clone()),
|
||||
}
|
||||
}
|
||||
@@ -1100,10 +1101,7 @@ fn default_read_only_subpaths_for_writable_root(
|
||||
protect_missing_dot_codex: bool,
|
||||
) -> Vec<AbsolutePathBuf> {
|
||||
let mut subpaths: Vec<AbsolutePathBuf> = Vec::new();
|
||||
#[allow(clippy::expect_used)]
|
||||
let top_level_git = writable_root
|
||||
.join(".git")
|
||||
.expect(".git is a valid relative path");
|
||||
let top_level_git = writable_root.join(".git");
|
||||
// This applies to typical repos (directory .git), worktrees/submodules
|
||||
// (file .git with gitdir pointer), and bare repos when the gitdir is the
|
||||
// writable root itself.
|
||||
@@ -1119,8 +1117,7 @@ fn default_read_only_subpaths_for_writable_root(
|
||||
subpaths.push(top_level_git);
|
||||
}
|
||||
|
||||
#[allow(clippy::expect_used)]
|
||||
let top_level_agents = writable_root.join(".agents").expect("valid relative path");
|
||||
let top_level_agents = writable_root.join(".agents");
|
||||
if top_level_agents.as_path().is_dir() {
|
||||
subpaths.push(top_level_agents);
|
||||
}
|
||||
@@ -1129,8 +1126,7 @@ fn default_read_only_subpaths_for_writable_root(
|
||||
// default. For the workspace root itself, protect it even before the
|
||||
// directory exists so first-time creation still goes through the
|
||||
// protected-path approval flow.
|
||||
#[allow(clippy::expect_used)]
|
||||
let top_level_codex = writable_root.join(".codex").expect("valid relative path");
|
||||
let top_level_codex = writable_root.join(".codex");
|
||||
if protect_missing_dot_codex || top_level_codex.as_path().is_dir() {
|
||||
subpaths.push(top_level_codex);
|
||||
}
|
||||
@@ -1227,16 +1223,7 @@ fn resolve_gitdir_from_file(dot_git: &AbsolutePathBuf) -> Option<AbsolutePathBuf
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let gitdir_path = match AbsolutePathBuf::resolve_path_against_base(gitdir_raw, base) {
|
||||
Ok(path) => path,
|
||||
Err(err) => {
|
||||
error!(
|
||||
"Failed to resolve gitdir path {gitdir_raw} from {path}: {err}",
|
||||
path = dot_git.as_path().display()
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let gitdir_path = AbsolutePathBuf::resolve_path_against_base(gitdir_raw, base);
|
||||
if !gitdir_path.as_path().exists() {
|
||||
error!(
|
||||
"Resolved gitdir path {path} does not exist.",
|
||||
@@ -1302,7 +1289,7 @@ mod tests {
|
||||
cwd.path().canonicalize().expect("canonicalize cwd"),
|
||||
)
|
||||
.expect("absolute canonical root");
|
||||
let expected_dot_codex = expected_root.join(".codex").expect("expected .codex path");
|
||||
let expected_dot_codex = expected_root.join(".codex");
|
||||
|
||||
let policy = FileSystemSandboxPolicy::restricted(vec![FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
@@ -1329,7 +1316,7 @@ mod tests {
|
||||
cwd.path().canonicalize().expect("canonicalize cwd"),
|
||||
)
|
||||
.expect("absolute canonical root");
|
||||
let explicit_dot_codex = expected_root.join(".codex").expect("expected .codex path");
|
||||
let explicit_dot_codex = expected_root.join(".codex");
|
||||
|
||||
let policy = FileSystemSandboxPolicy::restricted(vec![
|
||||
FileSystemSandboxEntry {
|
||||
@@ -1359,10 +1346,7 @@ mod tests {
|
||||
);
|
||||
assert!(
|
||||
policy.can_write_path_with_cwd(
|
||||
explicit_dot_codex
|
||||
.join("config.toml")
|
||||
.expect("config.toml")
|
||||
.as_path(),
|
||||
explicit_dot_codex.join("config.toml").as_path(),
|
||||
cwd.path()
|
||||
)
|
||||
);
|
||||
@@ -1451,7 +1435,7 @@ mod tests {
|
||||
|
||||
let link_root =
|
||||
AbsolutePathBuf::from_absolute_path(&link_root).expect("absolute symlinked root");
|
||||
let link_blocked = link_root.join("blocked").expect("symlinked blocked path");
|
||||
let link_blocked = link_root.join("blocked");
|
||||
let expected_root = AbsolutePathBuf::from_absolute_path(
|
||||
real_root.canonicalize().expect("canonicalize real root"),
|
||||
)
|
||||
@@ -1632,16 +1616,12 @@ mod tests {
|
||||
|
||||
let link_root =
|
||||
AbsolutePathBuf::from_absolute_path(&link_root).expect("absolute symlinked root");
|
||||
let link_private = link_root
|
||||
.join("linked-private")
|
||||
.expect("symlinked linked-private path");
|
||||
let link_private = link_root.join("linked-private");
|
||||
let expected_root = AbsolutePathBuf::from_absolute_path(
|
||||
real_root.canonicalize().expect("canonicalize real root"),
|
||||
)
|
||||
.expect("absolute canonical root");
|
||||
let expected_linked_private = expected_root
|
||||
.join("linked-private")
|
||||
.expect("expected linked-private path");
|
||||
let expected_linked_private = expected_root.join("linked-private");
|
||||
let unexpected_decoy =
|
||||
AbsolutePathBuf::from_absolute_path(decoy.canonicalize().expect("canonicalize decoy"))
|
||||
.expect("absolute canonical decoy");
|
||||
@@ -1686,16 +1666,12 @@ mod tests {
|
||||
|
||||
let link_root =
|
||||
AbsolutePathBuf::from_absolute_path(&link_root).expect("absolute symlinked root");
|
||||
let link_private = link_root
|
||||
.join("linked-private")
|
||||
.expect("symlinked linked-private path");
|
||||
let link_private = link_root.join("linked-private");
|
||||
let expected_root = AbsolutePathBuf::from_absolute_path(
|
||||
real_root.canonicalize().expect("canonicalize real root"),
|
||||
)
|
||||
.expect("absolute canonical root");
|
||||
let expected_linked_private = expected_root
|
||||
.join("linked-private")
|
||||
.expect("expected linked-private path");
|
||||
let expected_linked_private = expected_root.join("linked-private");
|
||||
let unexpected_decoy =
|
||||
AbsolutePathBuf::from_absolute_path(decoy.canonicalize().expect("canonicalize decoy"))
|
||||
.expect("absolute canonical decoy");
|
||||
@@ -1735,14 +1711,12 @@ mod tests {
|
||||
symlink_dir(&root, &alias).expect("create alias symlink");
|
||||
|
||||
let root = AbsolutePathBuf::from_absolute_path(&root).expect("absolute root");
|
||||
let alias = root.join("alias-root").expect("alias root path");
|
||||
let alias = root.join("alias-root");
|
||||
let expected_root = AbsolutePathBuf::from_absolute_path(
|
||||
root.as_path().canonicalize().expect("canonicalize root"),
|
||||
)
|
||||
.expect("absolute canonical root");
|
||||
let expected_alias = expected_root
|
||||
.join("alias-root")
|
||||
.expect("expected alias path");
|
||||
let expected_alias = expected_root.join("alias-root");
|
||||
|
||||
let policy = FileSystemSandboxPolicy::restricted(vec![
|
||||
FileSystemSandboxEntry {
|
||||
@@ -1848,13 +1822,10 @@ mod tests {
|
||||
#[test]
|
||||
fn resolve_access_with_cwd_uses_most_specific_entry() {
|
||||
let cwd = TempDir::new().expect("tempdir");
|
||||
let docs =
|
||||
AbsolutePathBuf::resolve_path_against_base("docs", cwd.path()).expect("resolve docs");
|
||||
let docs_private = AbsolutePathBuf::resolve_path_against_base("docs/private", cwd.path())
|
||||
.expect("resolve docs/private");
|
||||
let docs = AbsolutePathBuf::resolve_path_against_base("docs", cwd.path());
|
||||
let docs_private = AbsolutePathBuf::resolve_path_against_base("docs/private", cwd.path());
|
||||
let docs_private_public =
|
||||
AbsolutePathBuf::resolve_path_against_base("docs/private/public", cwd.path())
|
||||
.expect("resolve docs/private/public");
|
||||
AbsolutePathBuf::resolve_path_against_base("docs/private/public", cwd.path());
|
||||
let policy = FileSystemSandboxPolicy::restricted(vec![
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
@@ -1901,8 +1872,7 @@ mod tests {
|
||||
#[test]
|
||||
fn split_only_nested_carveouts_need_direct_runtime_enforcement() {
|
||||
let cwd = TempDir::new().expect("tempdir");
|
||||
let docs =
|
||||
AbsolutePathBuf::resolve_path_against_base("docs", cwd.path()).expect("resolve docs");
|
||||
let docs = AbsolutePathBuf::resolve_path_against_base("docs", cwd.path());
|
||||
let policy = FileSystemSandboxPolicy::restricted(vec![
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
@@ -1933,8 +1903,7 @@ mod tests {
|
||||
#[test]
|
||||
fn root_write_with_read_only_child_is_not_full_disk_write() {
|
||||
let cwd = TempDir::new().expect("tempdir");
|
||||
let docs =
|
||||
AbsolutePathBuf::resolve_path_against_base("docs", cwd.path()).expect("resolve docs");
|
||||
let docs = AbsolutePathBuf::resolve_path_against_base("docs", cwd.path());
|
||||
let policy = FileSystemSandboxPolicy::restricted(vec![
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
@@ -1961,8 +1930,7 @@ mod tests {
|
||||
#[test]
|
||||
fn root_deny_does_not_materialize_as_unreadable_root() {
|
||||
let cwd = TempDir::new().expect("tempdir");
|
||||
let docs =
|
||||
AbsolutePathBuf::resolve_path_against_base("docs", cwd.path()).expect("resolve docs");
|
||||
let docs = AbsolutePathBuf::resolve_path_against_base("docs", cwd.path());
|
||||
let expected_docs = AbsolutePathBuf::from_absolute_path(
|
||||
cwd.path()
|
||||
.canonicalize()
|
||||
@@ -2025,8 +1993,7 @@ mod tests {
|
||||
#[test]
|
||||
fn same_specificity_write_override_keeps_full_disk_write_access() {
|
||||
let cwd = TempDir::new().expect("tempdir");
|
||||
let docs =
|
||||
AbsolutePathBuf::resolve_path_against_base("docs", cwd.path()).expect("resolve docs");
|
||||
let docs = AbsolutePathBuf::resolve_path_against_base("docs", cwd.path());
|
||||
let policy = FileSystemSandboxPolicy::restricted(vec![
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
|
||||
@@ -1097,10 +1097,7 @@ fn default_read_only_subpaths_for_writable_root(
|
||||
protect_missing_dot_codex: bool,
|
||||
) -> Vec<AbsolutePathBuf> {
|
||||
let mut subpaths: Vec<AbsolutePathBuf> = Vec::new();
|
||||
#[allow(clippy::expect_used)]
|
||||
let top_level_git = writable_root
|
||||
.join(".git")
|
||||
.expect(".git is a valid relative path");
|
||||
let top_level_git = writable_root.join(".git");
|
||||
// This applies to typical repos (directory .git), worktrees/submodules
|
||||
// (file .git with gitdir pointer), and bare repos when the gitdir is the
|
||||
// writable root itself.
|
||||
@@ -1116,8 +1113,7 @@ fn default_read_only_subpaths_for_writable_root(
|
||||
subpaths.push(top_level_git);
|
||||
}
|
||||
|
||||
#[allow(clippy::expect_used)]
|
||||
let top_level_agents = writable_root.join(".agents").expect("valid relative path");
|
||||
let top_level_agents = writable_root.join(".agents");
|
||||
if top_level_agents.as_path().is_dir() {
|
||||
subpaths.push(top_level_agents);
|
||||
}
|
||||
@@ -1126,8 +1122,7 @@ fn default_read_only_subpaths_for_writable_root(
|
||||
// default. For the workspace root itself, protect it even before the
|
||||
// directory exists so first-time creation still goes through the
|
||||
// protected-path approval flow.
|
||||
#[allow(clippy::expect_used)]
|
||||
let top_level_codex = writable_root.join(".codex").expect("valid relative path");
|
||||
let top_level_codex = writable_root.join(".codex");
|
||||
if protect_missing_dot_codex || top_level_codex.as_path().is_dir() {
|
||||
subpaths.push(top_level_codex);
|
||||
}
|
||||
@@ -1187,16 +1182,7 @@ fn resolve_gitdir_from_file(dot_git: &AbsolutePathBuf) -> Option<AbsolutePathBuf
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let gitdir_path = match AbsolutePathBuf::resolve_path_against_base(gitdir_raw, base) {
|
||||
Ok(path) => path,
|
||||
Err(err) => {
|
||||
error!(
|
||||
"Failed to resolve gitdir path {gitdir_raw} from {path}: {err}",
|
||||
path = dot_git.as_path().display()
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let gitdir_path = AbsolutePathBuf::resolve_path_against_base(gitdir_raw, base);
|
||||
if !gitdir_path.as_path().exists() {
|
||||
error!(
|
||||
"Resolved gitdir path {path} does not exist.",
|
||||
@@ -4034,8 +4020,7 @@ mod tests {
|
||||
.last()
|
||||
.and_then(|path| AbsolutePathBuf::from_absolute_path(path).ok())
|
||||
.expect("filesystem root");
|
||||
let blocked = AbsolutePathBuf::resolve_path_against_base("blocked", cwd.path())
|
||||
.expect("resolve blocked");
|
||||
let blocked = AbsolutePathBuf::resolve_path_against_base("blocked", cwd.path());
|
||||
let expected_blocked = AbsolutePathBuf::from_absolute_path(
|
||||
cwd.path()
|
||||
.canonicalize()
|
||||
@@ -4086,8 +4071,7 @@ mod tests {
|
||||
let canonical_cwd = cwd.path().canonicalize().expect("canonicalize cwd");
|
||||
let cwd_absolute =
|
||||
AbsolutePathBuf::from_absolute_path(&canonical_cwd).expect("absolute tempdir");
|
||||
let secret = AbsolutePathBuf::resolve_path_against_base("secret", cwd.path())
|
||||
.expect("resolve unreadable path");
|
||||
let secret = AbsolutePathBuf::resolve_path_against_base("secret", cwd.path());
|
||||
let expected_secret = AbsolutePathBuf::from_absolute_path(canonical_cwd.join("secret"))
|
||||
.expect("canonical secret");
|
||||
let expected_agents = AbsolutePathBuf::from_absolute_path(canonical_cwd.join(".agents"))
|
||||
@@ -4152,10 +4136,8 @@ mod tests {
|
||||
fn restricted_file_system_policy_treats_read_entries_as_read_only_subpaths() {
|
||||
let cwd = TempDir::new().expect("tempdir");
|
||||
let canonical_cwd = cwd.path().canonicalize().expect("canonicalize cwd");
|
||||
let docs =
|
||||
AbsolutePathBuf::resolve_path_against_base("docs", cwd.path()).expect("resolve docs");
|
||||
let docs_public = AbsolutePathBuf::resolve_path_against_base("docs/public", cwd.path())
|
||||
.expect("resolve docs/public");
|
||||
let docs = AbsolutePathBuf::resolve_path_against_base("docs", cwd.path());
|
||||
let docs_public = AbsolutePathBuf::resolve_path_against_base("docs/public", cwd.path());
|
||||
let expected_docs = AbsolutePathBuf::from_absolute_path(canonical_cwd.join("docs"))
|
||||
.expect("canonical docs");
|
||||
let expected_docs_public =
|
||||
@@ -4199,8 +4181,7 @@ mod tests {
|
||||
#[test]
|
||||
fn legacy_workspace_write_nested_readable_root_stays_writable() {
|
||||
let cwd = TempDir::new().expect("tempdir");
|
||||
let docs =
|
||||
AbsolutePathBuf::resolve_path_against_base("docs", cwd.path()).expect("resolve docs");
|
||||
let docs = AbsolutePathBuf::resolve_path_against_base("docs", cwd.path());
|
||||
let canonical_cwd = cwd.path().canonicalize().expect("canonicalize cwd");
|
||||
let expected_dot_codex = AbsolutePathBuf::from_absolute_path(canonical_cwd.join(".codex"))
|
||||
.expect("canonical .codex");
|
||||
@@ -4257,12 +4238,9 @@ mod tests {
|
||||
#[test]
|
||||
fn legacy_sandbox_policy_semantics_survive_split_bridge() {
|
||||
let cwd = TempDir::new().expect("tempdir");
|
||||
let readable_root = AbsolutePathBuf::resolve_path_against_base("readable", cwd.path())
|
||||
.expect("resolve readable root");
|
||||
let writable_root = AbsolutePathBuf::resolve_path_against_base("writable", cwd.path())
|
||||
.expect("resolve writable root");
|
||||
let nested_readable_root = AbsolutePathBuf::resolve_path_against_base("docs", cwd.path())
|
||||
.expect("resolve nested readable root");
|
||||
let readable_root = AbsolutePathBuf::resolve_path_against_base("readable", cwd.path());
|
||||
let writable_root = AbsolutePathBuf::resolve_path_against_base("writable", cwd.path());
|
||||
let nested_readable_root = AbsolutePathBuf::resolve_path_against_base("docs", cwd.path());
|
||||
let policies = [
|
||||
SandboxPolicy::DangerFullAccess,
|
||||
SandboxPolicy::ExternalSandbox {
|
||||
|
||||
Reference in New Issue
Block a user