use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use crate::orchestration::{
pop_execution_policy, push_execution_policy, CapabilityPolicy, ExternalRoot, SandboxProfile,
ToolApprovalPolicy,
};
use crate::stdlib::sandbox::child_write::{child_write_disposition, ChildWriteDisposition};
use crate::tool_annotations::{SideEffectLevel, ToolAnnotations, ToolArgSchema, ToolKind};
fn confined_policy(
profile: SandboxProfile,
workspace: &Path,
read_only: &[&Path],
) -> CapabilityPolicy {
let mut annotations = BTreeMap::new();
annotations.insert(
"run".to_string(),
ToolAnnotations {
kind: ToolKind::Execute,
side_effect_level: SideEffectLevel::ProcessExec,
arg_schema: ToolArgSchema {
path_params: vec!["path".to_string()],
..Default::default()
},
..Default::default()
},
);
CapabilityPolicy {
capabilities: BTreeMap::from([
("process".to_string(), vec!["run".to_string()]),
(
"workspace".to_string(),
["read_text", "write_text", "list", "exists"]
.map(str::to_string)
.to_vec(),
),
]),
workspace_roots: vec![workspace.display().to_string()],
read_only_roots: read_only
.iter()
.map(|root| root.display().to_string())
.collect(),
side_effect_level: Some("process_exec".to_string()),
tool_annotations: annotations,
sandbox_profile: profile,
..Default::default()
}
}
fn run_admitted(policy: &CapabilityPolicy, root: &Path, path: &Path) -> bool {
crate::stdlib::sandbox::child_write::install_child_write_probe();
let approval = ToolApprovalPolicy {
external_roots: vec![ExternalRoot::read(root.display().to_string())],
..Default::default()
};
push_execution_policy(policy.clone());
let decision = approval.evaluate_detailed(
"run",
&serde_json::json!({ "path": path.display().to_string() }),
);
pop_execution_policy();
decision.is_allow()
}
#[cfg(any(target_os = "macos", target_os = "linux"))]
fn shell_succeeds(policy: &CapabilityPolicy, script: &str) -> bool {
push_execution_policy(policy.clone());
let output =
crate::stdlib::sandbox::std_command_for("/bin/sh", &["-c".to_string(), script.to_string()])
.and_then(|mut command| {
command
.output()
.map_err(|error| crate::value::VmError::Runtime(error.to_string()))
});
pop_execution_policy();
output.is_ok_and(|output| output.status.success())
}
fn canonical(path: &Path) -> PathBuf {
std::fs::canonicalize(path).unwrap()
}
fn workspace_and_outside() -> Option<(tempfile::TempDir, tempfile::TempDir)> {
let cwd = std::env::current_dir().ok()?;
let home = std::env::var_os("HOME").map(PathBuf::from)?;
if !home.is_dir() || home.starts_with("/tmp") || home.starts_with("/private/tmp") {
return None;
}
Some((
tempfile::tempdir_in(&cwd).ok()?,
tempfile::tempdir_in(home).ok()?,
))
}
#[cfg(any(target_os = "macos", target_os = "linux"))]
#[test]
fn a_command_under_an_enforced_read_only_root_is_admitted_and_cannot_write() {
if !crate::stdlib::sandbox::active_backend_filesystem_available() {
return;
}
let Some((workspace, outside)) = workspace_and_outside() else {
return;
};
let root = canonical(outside.path());
std::fs::create_dir_all(root.join("sub")).unwrap();
std::fs::write(root.join("data.txt"), "reference").unwrap();
let ws = canonical(workspace.path());
std::os::unix::fs::symlink(&root, ws.join("link")).unwrap();
let policy = confined_policy(SandboxProfile::OsHardened, &ws, &[root.as_path()]);
let file = root.join("data.txt");
assert_eq!(
child_write_disposition(&policy, &file),
ChildWriteDisposition::EnforcedReadOnly
);
assert!(
run_admitted(&policy, &root, &file),
"the boundary must admit the read"
);
assert!(
shell_succeeds(&policy, &format!("cat '{}'", file.display())),
"control: the child can read the root"
);
for (label, target) in [
("direct", root.join("f")),
("dot-dot", root.join("sub").join("..").join("f")),
("workspace symlink", ws.join("link").join("f")),
] {
assert!(
!shell_succeeds(&policy, &format!("echo x > '{}'", target.display())),
"{label}: the kernel must refuse a write into the read-only root"
);
assert!(!root.join("f").exists(), "{label}: nothing may be written");
}
assert_eq!(std::fs::read_to_string(&file).unwrap(), "reference");
assert!(shell_succeeds(
&policy,
&format!("echo x > '{}'", ws.join("ok.txt").display())
));
}
#[cfg(any(target_os = "macos", target_os = "linux"))]
#[test]
fn a_read_only_root_nested_in_the_workspace_is_judged_by_its_backend() {
if !crate::stdlib::sandbox::active_backend_filesystem_available() {
return;
}
let Some((workspace, _outside)) = workspace_and_outside() else {
return;
};
let ws = canonical(workspace.path());
let nested = ws.join("vendor");
std::fs::create_dir_all(&nested).unwrap();
let policy = confined_policy(SandboxProfile::OsHardened, &ws, &[nested.as_path()]);
let target = nested.join("f");
let write = format!("echo x > '{}'", target.display());
#[cfg(target_os = "macos")]
{
assert_eq!(
child_write_disposition(&policy, &target),
ChildWriteDisposition::EnforcedReadOnly
);
assert!(!shell_succeeds(&policy, &write));
assert!(!target.exists());
}
#[cfg(target_os = "linux")]
{
assert_eq!(
child_write_disposition(&policy, &target),
ChildWriteDisposition::Writable
);
assert!(
shell_succeeds(&policy, &write) && target.exists(),
"the oracle said writable, so the write must really land"
);
}
}
#[test]
fn only_os_hardened_can_admit() {
let Some((workspace, outside)) = workspace_and_outside() else {
return;
};
let root = canonical(outside.path());
let file = root.join("data.txt");
std::fs::write(&file, "reference").unwrap();
let ws = canonical(workspace.path());
for profile in [SandboxProfile::Unrestricted, SandboxProfile::Worktree] {
let policy = confined_policy(profile, &ws, &[root.as_path()]);
assert_eq!(
child_write_disposition(&policy, &file),
ChildWriteDisposition::Unknown,
"{profile:?}"
);
assert!(!run_admitted(&policy, &root, &file), "{profile:?}");
}
}
#[test]
fn a_command_with_no_active_policy_is_refused() {
let Some((_workspace, outside)) = workspace_and_outside() else {
return;
};
let root = canonical(outside.path());
let file = root.join("data.txt");
let approval = ToolApprovalPolicy {
external_roots: vec![ExternalRoot::read(root.display().to_string())],
..Default::default()
};
let decision = approval.evaluate_detailed(
"run",
&serde_json::json!({ "path": file.display().to_string() }),
);
assert!(!decision.is_allow(), "{}", decision.reason);
}
#[cfg(windows)]
#[test]
fn windows_never_admits() {
let workspace = tempfile::tempdir().unwrap();
let outside = tempfile::tempdir().unwrap();
let root = canonical(outside.path());
let file = root.join("data.txt");
std::fs::write(&file, "reference").unwrap();
let policy = confined_policy(
SandboxProfile::OsHardened,
&canonical(workspace.path()),
&[root.as_path()],
);
assert_eq!(
child_write_disposition(&policy, &file),
ChildWriteDisposition::Unknown
);
assert!(!run_admitted(&policy, &root, &file));
}