Make sandbox isolation behavior explicit and inspectable

This adds a small runtime sandbox policy/status layer, threads
sandbox options through the bash tool, and exposes `/sandbox`
status reporting in the CLI. Linux namespace/network isolation
is best-effort and intentionally reported as requested vs active
so the feature does not overclaim guarantees on unsupported
hosts or nested container environments.

Constraint: No new dependencies for isolation support
Constraint: Must keep filesystem restriction claims honest unless hard mount isolation succeeds
Rejected: External sandbox/container wrapper | too heavy for this workspace and request
Rejected: Inline bash-only changes without shared status model | weaker testability and poorer CLI visibility
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Treat this as observable best-effort isolation, not a hard security boundary, unless stronger mount enforcement is added later
Tested: cargo fmt --all; cargo clippy --workspace --all-targets --all-features -- -D warnings; cargo test --workspace
Not-tested: Manual `/sandbox` REPL run on a real nested-container host
This commit is contained in:
Yeachan-Heo
2026-04-01 01:14:38 +00:00
parent d6341d54c1
commit 2d09bf9961
9 changed files with 720 additions and 22 deletions

View File

@@ -62,7 +62,11 @@ pub fn mvp_tool_specs() -> Vec<ToolSpec> {
"timeout": { "type": "integer", "minimum": 1 },
"description": { "type": "string" },
"run_in_background": { "type": "boolean" },
"dangerouslyDisableSandbox": { "type": "boolean" }
"dangerouslyDisableSandbox": { "type": "boolean" },
"namespaceRestrictions": { "type": "boolean" },
"isolateNetwork": { "type": "boolean" },
"filesystemMode": { "type": "string", "enum": ["off", "workspace-only", "allow-list"] },
"allowedMounts": { "type": "array", "items": { "type": "string" } }
},
"required": ["command"],
"additionalProperties": false
@@ -2214,6 +2218,7 @@ fn execute_shell_command(
structured_content: None,
persisted_output_path: None,
persisted_output_size: None,
sandbox_status: None,
});
}
@@ -2251,6 +2256,7 @@ fn execute_shell_command(
structured_content: None,
persisted_output_path: None,
persisted_output_size: None,
sandbox_status: None,
});
}
if started.elapsed() >= Duration::from_millis(timeout_ms) {
@@ -2281,6 +2287,7 @@ Command exceeded timeout of {timeout_ms} ms",
structured_content: None,
persisted_output_path: None,
persisted_output_size: None,
sandbox_status: None,
});
}
std::thread::sleep(Duration::from_millis(10));
@@ -2307,6 +2314,7 @@ Command exceeded timeout of {timeout_ms} ms",
structured_content: None,
persisted_output_path: None,
persisted_output_size: None,
sandbox_status: None,
})
}