98 lines
3.0 KiB
Rust
98 lines
3.0 KiB
Rust
//! Compute allow/deny path sets from a sandbox policy.
|
|
|
|
use crate::policy::{SandboxMode, SandboxPolicy};
|
|
use dunce::canonicalize;
|
|
use std::collections::HashMap;
|
|
use std::collections::HashSet;
|
|
use std::path::Path;
|
|
use std::path::PathBuf;
|
|
|
|
#[derive(Debug, Default, PartialEq, Eq)]
|
|
pub struct AllowDenyPaths {
|
|
pub allow: HashSet<PathBuf>,
|
|
pub deny: HashSet<PathBuf>,
|
|
}
|
|
|
|
pub fn compute_allow_paths(
|
|
policy: &SandboxPolicy,
|
|
policy_cwd: &Path,
|
|
command_cwd: &Path,
|
|
env_map: &HashMap<String, String>,
|
|
) -> AllowDenyPaths {
|
|
let mut allow: HashSet<PathBuf> = HashSet::new();
|
|
let mut deny: HashSet<PathBuf> = HashSet::new();
|
|
|
|
let mut add_allow_path = |p: PathBuf| {
|
|
if p.exists() {
|
|
allow.insert(p);
|
|
}
|
|
};
|
|
let mut add_deny_path = |p: PathBuf| {
|
|
if p.exists() {
|
|
deny.insert(p);
|
|
}
|
|
};
|
|
|
|
if matches!(policy, SandboxPolicy::WorkspaceWrite { .. }) {
|
|
let add_writable_root =
|
|
|root: PathBuf, policy_cwd: &Path,
|
|
add_allow: &mut dyn FnMut(PathBuf), add_deny: &mut dyn FnMut(PathBuf)| {
|
|
let candidate = if root.is_absolute() {
|
|
root
|
|
} else {
|
|
policy_cwd.join(root)
|
|
};
|
|
let canonical = canonicalize(&candidate).unwrap_or(candidate);
|
|
add_allow(canonical.clone());
|
|
|
|
let git_dir = canonical.join(".git");
|
|
if git_dir.is_dir() {
|
|
add_deny(git_dir);
|
|
}
|
|
};
|
|
|
|
add_writable_root(
|
|
command_cwd.to_path_buf(),
|
|
policy_cwd,
|
|
&mut add_allow_path,
|
|
&mut add_deny_path,
|
|
);
|
|
|
|
if let SandboxPolicy::WorkspaceWrite { writable_roots, .. } = policy {
|
|
for root in writable_roots {
|
|
add_writable_root(
|
|
root.clone(),
|
|
policy_cwd,
|
|
&mut add_allow_path,
|
|
&mut add_deny_path,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Always include TEMP/TMP as writable roots
|
|
for key in ["TEMP", "TMP"] {
|
|
if let Some(v) = env_map.get(key) {
|
|
add_allow_path(PathBuf::from(v));
|
|
} else if let Ok(v) = std::env::var(key) {
|
|
add_allow_path(PathBuf::from(v));
|
|
}
|
|
}
|
|
|
|
// Include APPDATA/LOCALAPPDATA as writable roots in compat mode (and permissive).
|
|
// Strict mode intentionally excludes these — only workspace + TEMP/TMP are writable.
|
|
// This is the single authority for APPDATA allowance; the TypeScript side does NOT add them.
|
|
let mode = policy.sandbox_mode();
|
|
if mode != &SandboxMode::Strict {
|
|
for key in ["APPDATA", "LOCALAPPDATA"] {
|
|
if let Some(v) = env_map.get(key) {
|
|
add_allow_path(PathBuf::from(v));
|
|
} else if let Ok(v) = std::env::var(key) {
|
|
add_allow_path(PathBuf::from(v));
|
|
}
|
|
}
|
|
}
|
|
|
|
AllowDenyPaths { allow, deny }
|
|
}
|