6 KiB
6 KiB
Implementation Plan
Phase 4: Sandboxing
Step 4.1: Create sandbox module with policy types and tracing foundation
SandboxPolicystruct: read-only paths, read-write paths, network allowed boolSandboxstruct holding policy + working dir- Add
tracingspans and events throughout from the start:#[instrument]on all publicSandboxmethodsdebug!on policy construction with path listsinfo!on sandbox creation with full policy summary
- No enforcement yet, just the type skeleton and module wiring
- Files: new
src/sandbox/mod.rs,src/sandbox/policy.rs - Done when: compiles, unit tests for policy construction,
RUST_LOG=debug cargo testshows sandbox trace output
Step 4.2: Landlock policy builder with startup gate and tracing
- Translate
SandboxPolicyinto Landlock ruleset usinglandlockcrate - Kernel requirements:
- ABI v4 (kernel 6.7+): minimum required -- provides both filesystem and network sandboxing
- ABI 1-3 have filesystem only, no network restriction -- tools could exfiltrate data freely
- Startup behavior -- on launch, check Landlock ABI version:
- ABI >= 4: proceed normally (full filesystem + network sandboxing)
- ABI < 4 (including unsupported): refuse to start with clear error: "Landlock ABI v4+ required (kernel 6.7+). Use --yolo to run without sandboxing."
--yoloflag: skip all Landlock enforcement, logwarn!at startup, show "UNSANDBOXED" in status bar permanently
- Landlock applied per-child-process via
pre_exec, NOT to the main process- Main process needs unrestricted network (Claude API) and filesystem (provider)
- Each
exec_commandchild gets the current policy at spawn time :net on/offtakes effect on the next spawned command
- Tracing:
info!on kernel ABI version detecteddebug!for each rule added to ruleset (path, access flags)warn!on--yolomode ("running without kernel sandboxing")error!if ruleset creation fails unexpectedly
- Files:
src/sandbox/landlock.rs, addlandlockdep toCargo.toml, update CLI args insrc/app/ - Done when: unit test constructs ruleset without panic;
--yoloflag works on unsupported kernel; startup refuses without flag on unsupported kernel
Step 4.3: Sandbox file I/O API with operation tracing
Sandbox::read_file,Sandbox::write_file,Sandbox::list_directory- Move
validate_pathfromsrc/tools/mod.rsinto sandbox - Tracing:
debug!on every file operation: requested path, canonical path, allowed/deniedtrace!for path validation steps (join, canonicalize, starts_with check)warn!on path escape attempts (log the attempted path for debugging)debug!on successful operations with bytes read/written
- Files:
src/sandbox/mod.rs - Done when: unit tests in tempdir pass; path traversal rejected;
RUST_LOG=traceshows full path resolution chain
Step 4.4: Sandbox command execution with process tracing
Sandbox::exec_command(cmd, args, working_dir)spawns child process with Landlock applied- Captures stdout/stderr, enforces timeout
- Tracing:
info!on command spawn: command, args, working_dir, timeoutdebug!on command completion: exit code, stdout/stderr byte lengths, durationwarn!on non-zero exit codeserror!on timeout or spawn failure with full contexttrace!for Landlock application to child process thread
- Files:
src/sandbox/mod.rsorsrc/sandbox/exec.rs - Done when: unit test runs
echo helloin tempdir; write outside sandbox fails (on supported kernels)
Step 4.5: Wire tools through Sandbox
- Change
Tool::executesignature to accept&Sandboxinstead of (or in addition to)&Path - Update all 4 built-in tools to call
Sandboxmethods instead ofstd::fs/std::process::Command - Remove direct
std::fsusage from tool implementations - Update
ToolRegistryand orchestrator to passSandbox - Tracing: tools now inherit sandbox spans automatically via
#[instrument] - Files:
src/tools/*.rs,src/tools/mod.rs,src/core/orchestrator.rs - Done when: all existing tool tests pass through Sandbox; no direct
std::fsin tool files;RUST_LOG=debug cargo runshows sandbox operations during tool execution
Step 4.6: Network toggle
network_allowed: boolinSandboxPolicy:net on/offTUI command parsed in input handler, sent asUserAction::SetNetworkPolicy(bool)- Orchestrator updates
Sandboxpolicy. Status bar shows network state. - Only available when Landlock ABI >= 4 (kernel 6.7+); command hidden otherwise
- Status bar shows: network state when available, "UNSANDBOXED" in
--yolomode - Tracing:
info!on network policy change - Files:
src/tui/input.rs,src/tui/render.rs,src/core/types.rs,src/core/orchestrator.rs,src/sandbox/mod.rs - Done when: toggling
:netupdates status bar; Landlock network restriction applied on ABI >= 4
Step 4.7: Integration tests
- Tools + Sandbox in tempdir: write confinement, path traversal rejection, shell command confinement
- Skip Landlock-specific assertions on ABI < 4
- Test
--yolomode: sandbox constructed but no kernel enforcement - Test startup gate: verify error on ABI < 4 without
--yolo - Tests should assert tracing output where relevant (use
tracing-testcrate ortracing_subscriber::fmt::TestWriter) - Files:
tests/sandbox.rs - Done when:
cargo test --test sandboxpasses
Phase 4 verification (end-to-end)
cargo test-- all tests passcargo clippy -- -D warnings-- zero warningsRUST_LOG=debug cargo run -- --project-dir .-- ask Claude to read a file, observe sandbox trace logs showing path validation and Landlock policy- Ask Claude to write a file outside project dir -- sandbox denies with
warn!log - Ask Claude to run a shell command -- observe command spawn/completion trace
:net offthen ask for network access -- verify blocked- Without
--yoloon ABI < 4: verify startup refuses with clear error - With
--yolo: verify startup succeeds, "UNSANDBOXED" in status bar,warn!in logs