mirror of
https://github.com/openai/codex.git
synced 2026-10-19 16:17:49 +00:00
Add MXC sandbox integrity dependency and policy preparation (#51831)
## What changed Add Windows MXC backend helpers to inventory the Codex executable, sandbox launcher, and available `rg` scanner when deny globs are configured. Prepare filesystem policies for inspection by reusing MXC temporary-directory and volume resolution and replacing deny globs with concrete path snapshots. Allow Windows deny-glob resolution to run its scanner with an explicit command environment and working directory, including an empty environment. The integrity helpers are not yet invoked by an execution runner. ## Testing Add a backend test verifying that deny-glob snapshots replace the original patterns, including empty snapshots, and affect `FileContentsChecker` results. GitOrigin-RevId: 409c527663d230d76d65be3bf0a37959f694d77e
This commit is contained in:
Generated
+2
@@ -3214,6 +3214,7 @@ dependencies = [
|
||||
"codex-file-system",
|
||||
"codex-file-watcher",
|
||||
"codex-http-client",
|
||||
"codex-mxc-sandbox",
|
||||
"codex-network-proxy",
|
||||
"codex-otel",
|
||||
"codex-protocol",
|
||||
@@ -3260,6 +3261,7 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
"url",
|
||||
"uuid",
|
||||
"which 8.0.0",
|
||||
"windows-sys 0.61.2",
|
||||
"wiremock",
|
||||
]
|
||||
|
||||
@@ -80,6 +80,8 @@ rustix = { workspace = true, features = ["fs"] }
|
||||
tempfile = { workspace = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
codex-mxc-sandbox = { workspace = true }
|
||||
which = { workspace = true }
|
||||
windows-sys = { workspace = true, features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Security",
|
||||
|
||||
@@ -41,6 +41,12 @@ mod rpc;
|
||||
mod rpc_server_requests;
|
||||
mod rpc_timing;
|
||||
mod runtime_options;
|
||||
#[cfg(target_os = "windows")]
|
||||
#[expect(
|
||||
dead_code,
|
||||
reason = "The integrity runner is added later in this stack."
|
||||
)]
|
||||
mod sandbox_integrity;
|
||||
mod sandbox_selection;
|
||||
mod sandboxed_file_open;
|
||||
mod sandboxed_file_system;
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# Sandbox integrity: scope and review contract
|
||||
|
||||
These checks currently emit telemetry only. Findings and preparation errors must
|
||||
not change sandbox construction, permissions, approvals, or command execution.
|
||||
Supported backends are Seatbelt, bubblewrap, and MXC; legacy Windows is out of scope.
|
||||
|
||||
## Responsibilities
|
||||
|
||||
- Backends supply complete dependency inventories and interpret the request's
|
||||
original filesystem policy: resolve command temp directories and MXC volumes,
|
||||
and reuse the backend's deny-glob expansion where enforcement expands globs.
|
||||
- The runner prepares dependency facts and invokes each checker per dependency.
|
||||
Checkers remain independent of inventories and telemetry.
|
||||
Blocking work runs on the blocking pool with a five-second caller timeout.
|
||||
Timeouts use the existing check metric (`dependency=preparation`, `outcome=error`,
|
||||
`error_kind=timeout`). Late results are discarded; cancelling the blocking task
|
||||
or its scanner subprocess is deferred.
|
||||
- Telemetry derives bounded tags from the policy, dependency facts, and checker
|
||||
results. Never emit paths, environment values, or error text.
|
||||
A missing metrics client disables emission, never the checks themselves.
|
||||
Use the process-global metrics client; separately injected clients in programs
|
||||
embedding Codex are outside this phase's scope.
|
||||
|
||||
## Deliberate approximation
|
||||
|
||||
Honor the basic read/write/deny rules. Do not reconstruct native enforcement or
|
||||
audit OS ACLs. Additional backend protections can produce false positives;
|
||||
additional write grants (such as Seatbelt scratch access) can produce false
|
||||
negatives. Backend glob/symlink nuances and writable hard-link aliases are not
|
||||
fully modeled. The separate glob scan can differ from enforcement's snapshot.
|
||||
Metrics describe observed checker outcomes, not accuracy or missed violations.
|
||||
|
||||
Windows scanner discovery currently uses `which`, while enforcement uses
|
||||
`Command`. Their search-order and environment differences can select different
|
||||
executables or cause only one scan to use the internal walker. This is an accepted
|
||||
telemetry limitation for this phase; changing production scanner selection is deferred.
|
||||
|
||||
These are accepted limitations of this phase, not requests to duplicate backend
|
||||
implementations. Review against this scope. Regressions in explicit policy
|
||||
handling, executor context, or reporting remain actionable; this is not a blanket
|
||||
exemption for false positives or false negatives.
|
||||
|
||||
## Open eligibility issue
|
||||
|
||||
Approved escalations that retain only deny-read restrictions should be excluded.
|
||||
The current full-disk-write guard does not exclude `:root = write` plus denials,
|
||||
and `SandboxExecRequest` lacks the approval context to distinguish that escalation
|
||||
from a configured weak policy. Do not infer approval from policy shape.
|
||||
@@ -0,0 +1,67 @@
|
||||
//! Exercise backend policy preparation and dependency discovery.
|
||||
|
||||
use super::backend;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::permissions::FileSystemAccessMode;
|
||||
use codex_protocol::permissions::FileSystemPath;
|
||||
use codex_protocol::permissions::FileSystemSandboxEntry;
|
||||
use codex_protocol::permissions::FileSystemSandboxPolicy;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_protocol::sandbox::SandboxOverride;
|
||||
use codex_sandboxing::FileContentsChecker;
|
||||
use codex_sandboxing::SandboxExecRequest;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
|
||||
#[test]
|
||||
fn snapshot_denials_replace_patterns_including_an_empty_expansion() -> io::Result<()> {
|
||||
let temp = tempfile::tempdir()?;
|
||||
let root = AbsolutePathBuf::from_absolute_path(temp.path())?.canonicalize()?;
|
||||
let target = root.join("helper");
|
||||
fs::write(&target, "fixture")?;
|
||||
let policy = FileSystemSandboxPolicy::restricted(vec![
|
||||
FileSystemSandboxEntry::new(root.clone().into(), FileSystemAccessMode::Write),
|
||||
deny_glob(format!("{}/*", root.display())),
|
||||
]);
|
||||
for (expanded, writable) in [(vec![], true), (vec![target.clone()], false)] {
|
||||
let prepared = policy.clone().with_expanded_deny_globs(expanded);
|
||||
let checker = FileContentsChecker::new(&prepared, &root)?;
|
||||
assert_eq!(checker.check(&target)?.is_some(), writable);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn deny_glob(pattern: impl Into<String>) -> FileSystemSandboxEntry {
|
||||
FileSystemSandboxEntry::new(
|
||||
FileSystemPath::GlobPattern {
|
||||
pattern: pattern.into(),
|
||||
},
|
||||
FileSystemAccessMode::Deny,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn sandbox_request(
|
||||
cwd: &AbsolutePathBuf,
|
||||
policy: &FileSystemSandboxPolicy,
|
||||
) -> SandboxExecRequest {
|
||||
SandboxExecRequest {
|
||||
sandbox_override: SandboxOverride::NoOverride,
|
||||
command: vec![cwd.join("not-executed").to_string_lossy().into_owned()],
|
||||
cwd: PathUri::from_abs_path(cwd),
|
||||
sandbox_policy_cwd: PathUri::from_abs_path(cwd),
|
||||
env: Default::default(),
|
||||
network: None,
|
||||
network_environment_id: None,
|
||||
sandbox: backend::SANDBOX_TYPE,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
permission_profile: PermissionProfile::from_runtime_permissions(
|
||||
policy,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
),
|
||||
arg0: None,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//! Shared containment dependency inventory entries.
|
||||
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub(super) type Dependency = (&'static str, io::Result<PathBuf>);
|
||||
|
||||
pub(super) fn codex_executable() -> Dependency {
|
||||
("codex", std::env::current_exe())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
pub(super) fn codex_and_launcher_dependencies(
|
||||
request: &codex_sandboxing::SandboxExecRequest,
|
||||
) -> Vec<Dependency> {
|
||||
let mut dependencies = vec![codex_executable()];
|
||||
if let Some(exe) = request.command.first() {
|
||||
dependencies.push(("sandbox_launcher", Ok(PathBuf::from(exe))));
|
||||
}
|
||||
dependencies
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#[path = "mxc.rs"]
|
||||
mod backend;
|
||||
mod dependencies;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "backend_tests.rs"]
|
||||
mod backend_tests;
|
||||
@@ -0,0 +1,49 @@
|
||||
//! Discover MXC dependencies separately from resolving configured policy rules.
|
||||
|
||||
use super::dependencies::Dependency;
|
||||
use super::dependencies::codex_and_launcher_dependencies;
|
||||
use codex_protocol::permissions::FileSystemSandboxPolicy;
|
||||
use codex_sandboxing::SandboxExecRequest;
|
||||
use codex_sandboxing::SandboxType;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use std::io;
|
||||
|
||||
pub(super) const SANDBOX_TYPE: SandboxType = SandboxType::WindowsMxc;
|
||||
pub(super) const NAME: &str = "windows_mxc";
|
||||
|
||||
pub(super) fn critical_dependencies(
|
||||
request: &SandboxExecRequest,
|
||||
policy: &FileSystemSandboxPolicy,
|
||||
cwd: &AbsolutePathBuf,
|
||||
) -> io::Result<Vec<Dependency>> {
|
||||
let command_cwd = request.cwd.to_abs_path()?;
|
||||
let mut dependencies = codex_and_launcher_dependencies(request);
|
||||
if !policy
|
||||
.get_unreadable_globs_with_cwd(cwd.as_path())
|
||||
.is_empty()
|
||||
{
|
||||
let path = request
|
||||
.env
|
||||
.iter()
|
||||
.find(|(key, _)| key.eq_ignore_ascii_case("PATH"))
|
||||
.map(|(_, value)| value);
|
||||
if let Ok(scanner) = which::which_in(
|
||||
codex_mxc_sandbox::GLOB_SCAN_PROGRAM,
|
||||
path,
|
||||
command_cwd.as_path(),
|
||||
) {
|
||||
dependencies.push(("glob_scanner", Ok(scanner)));
|
||||
}
|
||||
}
|
||||
Ok(dependencies)
|
||||
}
|
||||
|
||||
pub(super) fn prepare_policy(
|
||||
request: &SandboxExecRequest,
|
||||
policy: FileSystemSandboxPolicy,
|
||||
cwd: &AbsolutePathBuf,
|
||||
) -> io::Result<FileSystemSandboxPolicy> {
|
||||
let command_cwd = request.cwd.to_abs_path()?;
|
||||
codex_mxc_sandbox::prepare_file_system_policy(policy, &request.env, cwd, command_cwd.as_path())
|
||||
.map_err(io::Error::other)
|
||||
}
|
||||
@@ -99,6 +99,43 @@ pub fn is_available() -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub use codex_windows_sandbox::GLOB_SCAN_PROGRAM;
|
||||
|
||||
/// Resolve configured symbols and snapshot deny globs for policy inspection.
|
||||
/// Reuses MXC's resolution without adding native grants or protections.
|
||||
#[cfg(windows)]
|
||||
pub fn prepare_file_system_policy(
|
||||
policy: codex_protocol::permissions::FileSystemSandboxPolicy,
|
||||
env: &HashMap<String, String>,
|
||||
policy_cwd: &codex_utils_absolute_path::AbsolutePathBuf,
|
||||
command_cwd: &Path,
|
||||
) -> Result<codex_protocol::permissions::FileSystemSandboxPolicy> {
|
||||
use codex_utils_path_uri::PathUri;
|
||||
|
||||
let env_entries = env
|
||||
.iter()
|
||||
.map(|(key, value)| format!("{key}={value}"))
|
||||
.collect::<Vec<_>>();
|
||||
let mut policy = policy::materialize_temporary_paths(policy, &env_entries)?;
|
||||
let denied = codex_windows_sandbox::resolve_windows_deny_read_paths_in_environment(
|
||||
&policy,
|
||||
policy_cwd,
|
||||
env,
|
||||
command_cwd,
|
||||
)
|
||||
.map_err(anyhow::Error::msg)?;
|
||||
policy = policy.with_expanded_deny_globs(denied);
|
||||
if policy.has_full_disk_write_access() {
|
||||
return Ok(policy);
|
||||
}
|
||||
let volumes = windows::volume_roots(policy_cwd.as_path(), command_cwd)?
|
||||
.into_iter()
|
||||
.map(PathUri::from_host_native_path)
|
||||
.collect::<std::io::Result<Vec<_>>>()?;
|
||||
Ok(policy::materialize_volume_roots(policy, &volumes)?)
|
||||
}
|
||||
|
||||
/// Entry point dispatched before ordinary Codex CLI parsing.
|
||||
pub fn run_main() -> ! {
|
||||
#[cfg(windows)]
|
||||
|
||||
@@ -70,25 +70,11 @@ pub enum PolicyError {
|
||||
CommandLine(#[from] CommandLineError),
|
||||
}
|
||||
|
||||
pub(super) fn build_request(
|
||||
command: &MxcCommand,
|
||||
command_cwd: &Path,
|
||||
env: Vec<String>,
|
||||
volume_roots: &[PathBuf],
|
||||
platform_read_roots: &[PathBuf],
|
||||
) -> Result<ExecutionRequest, PolicyError> {
|
||||
if command.command.is_empty() {
|
||||
return Err(PolicyError::EmptyCommand);
|
||||
}
|
||||
let permissions = &command.permissions;
|
||||
let cwd = &command.sandbox_policy_cwd;
|
||||
if !cwd.is_absolute() {
|
||||
return Err(PolicyError::RelativePolicyCwd);
|
||||
}
|
||||
if !command_cwd.is_absolute() {
|
||||
return Err(PolicyError::RelativeCommandCwd);
|
||||
}
|
||||
let mut policy = permissions.file_system_sandbox_policy();
|
||||
/// Bind MXC's temporary-directory symbols using the filtered command environment.
|
||||
pub(super) fn materialize_temporary_paths(
|
||||
mut policy: FileSystemSandboxPolicy,
|
||||
env: &[String],
|
||||
) -> std::io::Result<FileSystemSandboxPolicy> {
|
||||
// Resolve Windows temporary directories from the filtered command
|
||||
// environment, including case-insensitive names.
|
||||
let mut temp_values = HashMap::new();
|
||||
@@ -126,6 +112,28 @@ pub(super) fn build_request(
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Ok(policy)
|
||||
}
|
||||
|
||||
pub(super) fn build_request(
|
||||
command: &MxcCommand,
|
||||
command_cwd: &Path,
|
||||
env: Vec<String>,
|
||||
volume_roots: &[PathBuf],
|
||||
platform_read_roots: &[PathBuf],
|
||||
) -> Result<ExecutionRequest, PolicyError> {
|
||||
if command.command.is_empty() {
|
||||
return Err(PolicyError::EmptyCommand);
|
||||
}
|
||||
let permissions = &command.permissions;
|
||||
let cwd = &command.sandbox_policy_cwd;
|
||||
if !cwd.is_absolute() {
|
||||
return Err(PolicyError::RelativePolicyCwd);
|
||||
}
|
||||
if !command_cwd.is_absolute() {
|
||||
return Err(PolicyError::RelativeCommandCwd);
|
||||
}
|
||||
let policy = materialize_temporary_paths(permissions.file_system_sandbox_policy(), &env)?;
|
||||
let full_disk_write = policy.has_full_disk_write_access();
|
||||
let volumes = volume_roots
|
||||
.iter()
|
||||
|
||||
@@ -48,23 +48,8 @@ pub(super) fn run() -> Result<i32> {
|
||||
.map_err(|_| anyhow::anyhow!("invalid MXC launcher request"))?;
|
||||
// The transport itself proves this is an explicit child environment; it
|
||||
// may intentionally contain no variables once launcher state is removed.
|
||||
let mask = unsafe { GetLogicalDrives() };
|
||||
ensure!(
|
||||
mask != 0,
|
||||
"cannot enumerate Windows volumes: {}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
let mut volumes: Vec<PathBuf> = (0..26)
|
||||
.filter(|index| mask & (1 << index) != 0)
|
||||
.map(|index| PathBuf::from(format!("{}:\\", (b'A' + index as u8) as char)))
|
||||
.collect();
|
||||
let command_cwd = std::env::current_dir()?;
|
||||
// An explicit UNC cwd has no drive letter and is absent from GetLogicalDrives.
|
||||
for cwd in [&command.sandbox_policy_cwd, &command_cwd] {
|
||||
if let Some(root) = cwd.ancestors().last() {
|
||||
volumes.push(root.to_path_buf());
|
||||
}
|
||||
}
|
||||
let volumes = volume_roots(&command.sandbox_policy_cwd, &command_cwd)?;
|
||||
let request = crate::policy::build_request(
|
||||
&command,
|
||||
&command_cwd,
|
||||
@@ -77,6 +62,29 @@ pub(super) fn run() -> Result<i32> {
|
||||
crate::native::launch(&request)
|
||||
}
|
||||
|
||||
pub(super) fn volume_roots(
|
||||
policy_cwd: &std::path::Path,
|
||||
command_cwd: &std::path::Path,
|
||||
) -> Result<Vec<PathBuf>> {
|
||||
let mask = unsafe { GetLogicalDrives() };
|
||||
ensure!(
|
||||
mask != 0,
|
||||
"cannot enumerate Windows volumes: {}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
let mut volumes: Vec<PathBuf> = (0..26)
|
||||
.filter(|index| mask & (1 << index) != 0)
|
||||
.map(|index| PathBuf::from(format!("{}:\\", (b'A' + index as u8) as char)))
|
||||
.collect();
|
||||
// An explicit UNC cwd has no drive letter and is absent from GetLogicalDrives.
|
||||
for cwd in [policy_cwd, command_cwd] {
|
||||
if let Some(root) = cwd.ancestors().last() {
|
||||
volumes.push(root.to_path_buf());
|
||||
}
|
||||
}
|
||||
Ok(volumes)
|
||||
}
|
||||
|
||||
fn platform_read_roots() -> Result<Vec<PathBuf>> {
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
|
||||
|
||||
@@ -1838,6 +1838,19 @@ impl FileSystemSandboxPolicy {
|
||||
patterns
|
||||
}
|
||||
|
||||
/// Replace deny globs with a backend's concrete snapshot, preserving other entries.
|
||||
/// An empty snapshot still removes the original patterns.
|
||||
pub fn with_expanded_deny_globs(mut self, paths: Vec<AbsolutePathBuf>) -> Self {
|
||||
self.entries
|
||||
.retain(|entry| !matches!(entry.path, FileSystemPath::GlobPattern { .. }));
|
||||
self.entries.extend(
|
||||
paths
|
||||
.into_iter()
|
||||
.map(|path| FileSystemSandboxEntry::new(path.into(), FileSystemAccessMode::Deny)),
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn to_legacy_sandbox_policy(
|
||||
&self,
|
||||
network_policy: NetworkSandboxPolicy,
|
||||
|
||||
@@ -5,8 +5,11 @@ use codex_protocol::permissions::FileSystemSandboxPolicy;
|
||||
use codex_protocol::permissions::ReadDenyMatcher;
|
||||
use codex_protocol::permissions::windows_deny_read_glob_scan;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
#[path = "deny_read_walker.rs"]
|
||||
mod walker;
|
||||
@@ -14,6 +17,9 @@ mod walker;
|
||||
use walker::DirectoryScanMode;
|
||||
use walker::collect_existing_glob_directory_matches;
|
||||
|
||||
/// External scanner used by deny-glob expansion and its dependency inventory.
|
||||
pub const GLOB_SCAN_PROGRAM: &str = "rg";
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
struct GlobScanPlan {
|
||||
root: PathBuf,
|
||||
@@ -31,6 +37,27 @@ struct GlobScanPlan {
|
||||
pub fn resolve_windows_deny_read_paths(
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
cwd: &AbsolutePathBuf,
|
||||
) -> Result<Vec<AbsolutePathBuf>, String> {
|
||||
resolve_deny_read_paths(file_system_sandbox_policy, cwd, |_| {})
|
||||
}
|
||||
|
||||
/// Resolve deny paths with the launcher's scanner in an explicit command environment.
|
||||
/// The supplied environment replaces inheritance, including when it is empty.
|
||||
pub fn resolve_windows_deny_read_paths_in_environment(
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
cwd: &AbsolutePathBuf,
|
||||
env: &HashMap<String, String>,
|
||||
command_cwd: &Path,
|
||||
) -> Result<Vec<AbsolutePathBuf>, String> {
|
||||
resolve_deny_read_paths(file_system_sandbox_policy, cwd, |command| {
|
||||
command.env_clear().envs(env).current_dir(command_cwd);
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_deny_read_paths(
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
cwd: &AbsolutePathBuf,
|
||||
configure: impl Fn(&mut Command),
|
||||
) -> Result<Vec<AbsolutePathBuf>, String> {
|
||||
let mut paths = Vec::new();
|
||||
let mut seen = HashSet::new();
|
||||
@@ -71,7 +98,7 @@ pub fn resolve_windows_deny_read_paths(
|
||||
continue;
|
||||
}
|
||||
|
||||
let directory_scan_mode = if let Some(file_paths) = ripgrep_files(&scan_plan)? {
|
||||
let directory_scan_mode = if let Some(file_paths) = ripgrep_files(&scan_plan, &configure)? {
|
||||
for path in file_paths {
|
||||
if matcher.is_local_path_read_denied(&path) {
|
||||
push_absolute_path(&mut paths, &mut seen, path)?;
|
||||
@@ -98,8 +125,12 @@ pub fn resolve_windows_deny_read_paths(
|
||||
Ok(paths)
|
||||
}
|
||||
|
||||
fn ripgrep_files(scan_plan: &GlobScanPlan) -> Result<Option<Vec<PathBuf>>, String> {
|
||||
let mut command = codex_utils_process::background_command("rg");
|
||||
fn ripgrep_files(
|
||||
scan_plan: &GlobScanPlan,
|
||||
configure: &impl Fn(&mut Command),
|
||||
) -> Result<Option<Vec<PathBuf>>, String> {
|
||||
let mut command = codex_utils_process::background_command(GLOB_SCAN_PROGRAM);
|
||||
configure(&mut command);
|
||||
command
|
||||
.arg("--files")
|
||||
.arg("--hidden")
|
||||
@@ -512,11 +543,14 @@ mod tests {
|
||||
tmp.path().display()
|
||||
))]);
|
||||
|
||||
if let Some(paths) = super::ripgrep_files(&GlobScanPlan {
|
||||
root: tmp.path().to_path_buf(),
|
||||
max_depth: None,
|
||||
globs: vec!["**/*.env".to_string()],
|
||||
})
|
||||
if let Some(paths) = super::ripgrep_files(
|
||||
&GlobScanPlan {
|
||||
root: tmp.path().to_path_buf(),
|
||||
max_depth: None,
|
||||
globs: vec!["**/*.env".to_string()],
|
||||
},
|
||||
&|_| {},
|
||||
)
|
||||
.expect("case-insensitive ripgrep scan")
|
||||
{
|
||||
assert!(paths.contains(&uppercase_env));
|
||||
|
||||
@@ -263,7 +263,9 @@ pub use conpty::spawn_conpty_process_as_user;
|
||||
pub use deny_read_acl::apply_deny_read_acls;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use deny_read_acl::plan_deny_read_acl_paths;
|
||||
pub use deny_read_resolver::GLOB_SCAN_PROGRAM;
|
||||
pub use deny_read_resolver::resolve_windows_deny_read_paths;
|
||||
pub use deny_read_resolver::resolve_windows_deny_read_paths_in_environment;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use deny_read_state::sync_persistent_deny_read_acls;
|
||||
#[cfg(target_os = "windows")]
|
||||
|
||||
Reference in New Issue
Block a user