mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
add a slash command to grant sandbox read access to inaccessible directories (#11512)
There is an edge case where a directory is not readable by the sandbox. In practice, we've seen very little of it, but it can happen so this slash command unlocks users when it does. Future idea is to make this a tool that the agent knows about so it can be more integrated.
This commit is contained in:
committed by
GitHub
Unverified
parent
466be55abc
commit
5c3ca73914
@@ -79,6 +79,7 @@ pub mod review_format;
|
||||
pub mod review_prompts;
|
||||
mod thread_manager;
|
||||
pub mod web_search;
|
||||
pub mod windows_sandbox_read_grants;
|
||||
pub use codex_protocol::protocol::InitialHistory;
|
||||
pub use thread_manager::NewThread;
|
||||
pub use thread_manager::ThreadManager;
|
||||
|
||||
@@ -10,6 +10,7 @@ use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Kill switch for the elevated sandbox NUX on Windows.
|
||||
///
|
||||
@@ -200,6 +201,25 @@ pub fn run_legacy_setup_preflight(
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn run_setup_refresh_with_extra_read_roots(
|
||||
policy: &SandboxPolicy,
|
||||
policy_cwd: &Path,
|
||||
command_cwd: &Path,
|
||||
env_map: &HashMap<String, String>,
|
||||
codex_home: &Path,
|
||||
extra_read_roots: Vec<PathBuf>,
|
||||
) -> anyhow::Result<()> {
|
||||
codex_windows_sandbox::run_setup_refresh_with_extra_read_roots(
|
||||
policy,
|
||||
policy_cwd,
|
||||
command_cwd,
|
||||
env_map,
|
||||
codex_home,
|
||||
extra_read_roots,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn run_legacy_setup_preflight(
|
||||
_policy: &SandboxPolicy,
|
||||
@@ -211,6 +231,18 @@ pub fn run_legacy_setup_preflight(
|
||||
anyhow::bail!("legacy Windows sandbox setup is only supported on Windows")
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn run_setup_refresh_with_extra_read_roots(
|
||||
_policy: &SandboxPolicy,
|
||||
_policy_cwd: &Path,
|
||||
_command_cwd: &Path,
|
||||
_env_map: &HashMap<String, String>,
|
||||
_codex_home: &Path,
|
||||
_extra_read_roots: Vec<PathBuf>,
|
||||
) -> anyhow::Result<()> {
|
||||
anyhow::bail!("Windows sandbox read-root refresh is only supported on Windows")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
use crate::protocol::SandboxPolicy;
|
||||
use crate::windows_sandbox::run_setup_refresh_with_extra_read_roots;
|
||||
use anyhow::Result;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn grant_read_root_non_elevated(
|
||||
policy: &SandboxPolicy,
|
||||
policy_cwd: &Path,
|
||||
command_cwd: &Path,
|
||||
env_map: &HashMap<String, String>,
|
||||
codex_home: &Path,
|
||||
read_root: &Path,
|
||||
) -> Result<PathBuf> {
|
||||
if !read_root.is_absolute() {
|
||||
anyhow::bail!("path must be absolute: {}", read_root.display());
|
||||
}
|
||||
if !read_root.exists() {
|
||||
anyhow::bail!("path does not exist: {}", read_root.display());
|
||||
}
|
||||
if !read_root.is_dir() {
|
||||
anyhow::bail!("path must be a directory: {}", read_root.display());
|
||||
}
|
||||
|
||||
let canonical_root = dunce::canonicalize(read_root)?;
|
||||
run_setup_refresh_with_extra_read_roots(
|
||||
policy,
|
||||
policy_cwd,
|
||||
command_cwd,
|
||||
env_map,
|
||||
codex_home,
|
||||
vec![canonical_root.clone()],
|
||||
)?;
|
||||
Ok(canonical_root)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::grant_read_root_non_elevated;
|
||||
use crate::protocol::SandboxPolicy;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn policy() -> SandboxPolicy {
|
||||
SandboxPolicy::new_workspace_write_policy()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_relative_path() {
|
||||
let tmp = TempDir::new().expect("tempdir");
|
||||
let err = grant_read_root_non_elevated(
|
||||
&policy(),
|
||||
tmp.path(),
|
||||
tmp.path(),
|
||||
&HashMap::new(),
|
||||
tmp.path(),
|
||||
Path::new("relative"),
|
||||
)
|
||||
.expect_err("relative path should fail");
|
||||
assert!(err.to_string().contains("path must be absolute"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_missing_path() {
|
||||
let tmp = TempDir::new().expect("tempdir");
|
||||
let missing = tmp.path().join("does-not-exist");
|
||||
let err = grant_read_root_non_elevated(
|
||||
&policy(),
|
||||
tmp.path(),
|
||||
tmp.path(),
|
||||
&HashMap::new(),
|
||||
tmp.path(),
|
||||
missing.as_path(),
|
||||
)
|
||||
.expect_err("missing path should fail");
|
||||
assert!(err.to_string().contains("path does not exist"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_file_path() {
|
||||
let tmp = TempDir::new().expect("tempdir");
|
||||
let file_path = tmp.path().join("file.txt");
|
||||
std::fs::write(&file_path, "hello").expect("write file");
|
||||
let err = grant_read_root_non_elevated(
|
||||
&policy(),
|
||||
tmp.path(),
|
||||
tmp.path(),
|
||||
&HashMap::new(),
|
||||
tmp.path(),
|
||||
file_path.as_path(),
|
||||
)
|
||||
.expect_err("file path should fail");
|
||||
assert!(err.to_string().contains("path must be a directory"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user