docs(sandbox): define windows helper contract
This commit is contained in:
committed by
Hunter Bown
parent
e814a203cb
commit
451d66ab0a
@@ -10,7 +10,9 @@
|
||||
//!
|
||||
//! - **macOS**: Uses Seatbelt (sandbox-exec) for mandatory access control
|
||||
//! - **Linux**: Uses Landlock (kernel 5.13+) for filesystem access control
|
||||
//! - **Windows**: Windows Sandbox/AppContainer/Restricted token (best-effort)
|
||||
//! - **Windows**: No OS sandbox is advertised yet. The planned first helper
|
||||
//! contract is process-tree containment only via a Windows Job Object; it
|
||||
//! must not claim filesystem, network, registry, or AppContainer isolation.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
@@ -179,7 +181,10 @@ pub enum SandboxType {
|
||||
#[cfg(target_os = "linux")]
|
||||
LinuxLandlock,
|
||||
|
||||
/// Windows sandboxing (Windows Sandbox/AppContainer/Restricted token).
|
||||
/// Windows process-containment helper.
|
||||
///
|
||||
/// Not advertised until a helper enforces Job Object cleanup. This does
|
||||
/// not imply filesystem, network, registry, or AppContainer isolation.
|
||||
#[cfg(target_os = "windows")]
|
||||
Windows,
|
||||
}
|
||||
@@ -427,10 +432,12 @@ impl SandboxManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare a Windows-sandboxed execution environment.
|
||||
/// Prepare a Windows helper execution environment.
|
||||
///
|
||||
/// Note: Windows sandboxing requires a helper process for full isolation.
|
||||
/// This implementation marks intent and defers enforcement to a helper.
|
||||
/// Windows support is currently not advertised by `get_platform_sandbox`.
|
||||
/// This branch only exists for forced tests and future helper wiring.
|
||||
/// The first supported helper contract is process-tree containment only;
|
||||
/// it must not be presented as filesystem or network isolation.
|
||||
#[cfg(target_os = "windows")]
|
||||
fn prepare_windows(spec: &CommandSpec) -> ExecEnv {
|
||||
let mut command = vec![spec.program.clone()];
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
//! Windows sandbox implementation (best-effort placeholder).
|
||||
//! Windows sandbox helper contract.
|
||||
//!
|
||||
//! Windows sandboxing can be implemented using:
|
||||
//! - Windows Sandbox (full isolation)
|
||||
//! - AppContainer (process isolation)
|
||||
//! - Restricted tokens (reduced privileges)
|
||||
//! Current status: DeepSeek TUI does not advertise an in-process Windows
|
||||
//! sandbox. Future Windows support must run commands through a dedicated
|
||||
//! helper that provides process-tree containment with a Job Object and
|
||||
//! `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`.
|
||||
//!
|
||||
//! This module selects a preferred approach and exposes helpers used by the
|
||||
//! sandbox manager. Full enforcement should be implemented in a helper binary.
|
||||
//! The first Windows helper slice is process containment only. It must not
|
||||
//! claim read-only filesystem isolation, workspace-write enforcement, network
|
||||
//! blocking, registry isolation, or AppContainer-level isolation until those
|
||||
//! guarantees are implemented and tested separately.
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
@@ -14,33 +16,23 @@ use super::SandboxPolicy;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum WindowsSandboxKind {
|
||||
WindowsSandbox,
|
||||
AppContainer,
|
||||
RestrictedToken,
|
||||
ProcessContainment,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for WindowsSandboxKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
WindowsSandboxKind::WindowsSandbox => write!(f, "sandbox"),
|
||||
WindowsSandboxKind::AppContainer => write!(f, "appcontainer"),
|
||||
WindowsSandboxKind::RestrictedToken => write!(f, "restricted-token"),
|
||||
WindowsSandboxKind::ProcessContainment => write!(f, "process-containment"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_available() -> bool {
|
||||
windows_sandbox_available() || appcontainer_available() || restricted_token_available()
|
||||
false
|
||||
}
|
||||
|
||||
pub fn select_best_kind(_policy: &SandboxPolicy, _cwd: &Path) -> WindowsSandboxKind {
|
||||
if windows_sandbox_available() {
|
||||
WindowsSandboxKind::WindowsSandbox
|
||||
} else if appcontainer_available() {
|
||||
WindowsSandboxKind::AppContainer
|
||||
} else {
|
||||
WindowsSandboxKind::RestrictedToken
|
||||
}
|
||||
WindowsSandboxKind::ProcessContainment
|
||||
}
|
||||
|
||||
pub fn detect_denial(exit_code: i32, stderr: &str) -> bool {
|
||||
@@ -59,21 +51,16 @@ pub fn detect_denial(exit_code: i32, stderr: &str) -> bool {
|
||||
|
||||
patterns.iter().any(|p| stderr.contains(p))
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn windows_sandbox_available() -> bool {
|
||||
let Ok(system_root) = std::env::var("SystemRoot") else {
|
||||
return false;
|
||||
};
|
||||
Path::new(&system_root)
|
||||
.join("System32")
|
||||
.join("WindowsSandbox.exe")
|
||||
.exists()
|
||||
}
|
||||
|
||||
fn appcontainer_available() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn restricted_token_available() -> bool {
|
||||
true
|
||||
#[test]
|
||||
fn windows_sandbox_is_not_advertised_until_helper_exists() {
|
||||
assert!(!is_available());
|
||||
assert_eq!(
|
||||
select_best_kind(&SandboxPolicy::default(), Path::new(".")),
|
||||
WindowsSandboxKind::ProcessContainment
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,10 +161,13 @@ drives turns through Chat Completions.
|
||||
|
||||
### Security
|
||||
|
||||
- **`sandbox/`** - macOS sandboxing support
|
||||
- **`sandbox/`** - platform sandbox policy preparation and denial reporting
|
||||
- `mod.rs` - Sandbox type definitions
|
||||
- `policy.rs` - Sandbox policy configuration
|
||||
- `seatbelt.rs` - macOS Seatbelt profile generation
|
||||
- `landlock.rs` - Linux Landlock detection and future helper contract
|
||||
- `windows.rs` - Windows helper contract; not advertised until a Job
|
||||
Object process-containment helper exists
|
||||
|
||||
### Utilities
|
||||
|
||||
@@ -281,7 +284,10 @@ command = "echo 'Running tool: $TOOL_NAME'"
|
||||
1. **Streaming-first**: All LLM responses stream for responsiveness
|
||||
2. **Tool safety**: Non-YOLO mode requires approval for destructive operations, including side-effectful MCP tools
|
||||
3. **Extensibility**: MCP, skills, and hooks allow customization without code changes
|
||||
4. **Cross-platform**: Core works on Linux/macOS/Windows, sandboxing macOS-only
|
||||
4. **Cross-platform**: Core works on Linux/macOS/Windows. Sandbox guarantees
|
||||
are platform-specific: macOS Seatbelt is the active policy path; Linux and
|
||||
Windows require helper enforcement before they should be treated as full OS
|
||||
sandboxing.
|
||||
5. **Minimal dependencies**: Careful dependency selection for build speed
|
||||
6. **Local-first runtime API**: HTTP/SSE endpoints are intended for trusted localhost access and are served by the `crates/tui` runtime today
|
||||
|
||||
|
||||
@@ -364,6 +364,12 @@ If you are upgrading from older releases:
|
||||
- `allow_shell` (bool, optional): defaults to `true` (sandboxed).
|
||||
- `approval_policy` (string, optional): `on-request`, `untrusted`, or `never`. Runtime `approval_mode` editing in `/config` also accepts `on-request` and `untrusted` aliases.
|
||||
- `sandbox_mode` (string, optional): `read-only`, `workspace-write`, `danger-full-access`, `external-sandbox`.
|
||||
Platform support is not identical. macOS uses Seatbelt for policy
|
||||
enforcement. Linux support is helper-gated around Landlock. Windows does not
|
||||
currently advertise an OS sandbox; the planned Windows helper contract starts
|
||||
with process-tree containment only and must not be described as read-only
|
||||
filesystem isolation, workspace-write enforcement, network blocking,
|
||||
registry isolation, or AppContainer isolation until those are implemented.
|
||||
- `managed_config_path` (string, optional): managed config file loaded after user/env config.
|
||||
- `requirements_path` (string, optional): requirements file used to enforce allowed approval/sandbox values.
|
||||
- `max_subagents` (int, optional): defaults to `10` and is clamped to `1..=20`.
|
||||
|
||||
Reference in New Issue
Block a user