pub struct Sandbox { /* private fields */ }Implementations§
Source§impl Sandbox
impl Sandbox
pub fn new(cfg: SandboxConfig) -> Self
pub fn backend(&self) -> Backend
Sourcepub fn with_network(&self, network: bool) -> Self
pub fn with_network(&self, network: bool) -> Self
The same policy with the network decided differently.
Exists because network is otherwise one switch for everything, and the
common case wants them split: a third-party MCP server that has to reach
its own API, confined, while shell still has no way out. Sharing one
flag would mean opening shell to satisfy the server.
pub fn is_enabled(&self) -> bool
Sourcepub fn can_reach_network(&self) -> bool
pub fn can_reach_network(&self) -> bool
Can a confined command still reach off this machine?
This is what decides whether shell counts as an external_send sink.
Unconfined, it always can. Confined without network, it cannot — and the
interlock should stop treating it as a way out, because it isn’t one.
Sourcepub fn reaches_beyond_workspace(&self) -> bool
pub fn reaches_beyond_workspace(&self) -> bool
Can a confined command read data outside the workspace?
Unconfined it reads your whole home directory. Confined it sees the
workspace and a read-only system — the same reach fs_read already has,
which is classified private on the same reasoning.
Sourcepub fn command(
&self,
command: &str,
workspace: &Path,
cwd: &Path,
) -> Result<Command>
pub fn command( &self, command: &str, workspace: &Path, cwd: &Path, ) -> Result<Command>
Build the process that will run command.
workspace is mounted writable; cwd must be inside it — the caller has
already proved that through ToolCtx::resolve.
Sourcepub fn wrap_argv(
&self,
program: &str,
args: &[String],
workspace: &Path,
cwd: &Path,
) -> Result<Command>
pub fn wrap_argv( &self, program: &str, args: &[String], workspace: &Path, cwd: &Path, ) -> Result<Command>
Confine an explicit argv, with no shell in between.
For long-lived children — an MCP server — where routing through
bash -lc would mean quoting caller-supplied arguments correctly, and
getting that wrong is a command-injection bug rather than a typo.
Sourcepub fn child_env(passthrough: &[String]) -> Vec<(String, String)>
pub fn child_env(passthrough: &[String]) -> Vec<(String, String)>
The environment a child should get, given a passthrough allowlist.
Inheriting mecha’s environment hands a third-party process every secret you have exported — provider keys first among them. So the rule is the same as inside the sandbox: a minimal base, plus what was named.
HOME and PATH are in the base because without them most runtimes
(node, python) cannot find their own modules, and a server that cannot
start teaches the operator to turn this off.
Sourcepub fn bwrap_args(&self, workspace: &Path, cwd: &Path) -> Result<Vec<String>>
pub fn bwrap_args(&self, workspace: &Path, cwd: &Path) -> Result<Vec<String>>
Arguments up to (but not including) the command itself. Split out so the policy can be asserted on in tests without spawning anything.
Sourcepub fn docker_args(&self, workspace: &Path, cwd: &Path) -> Result<Vec<String>>
pub fn docker_args(&self, workspace: &Path, cwd: &Path) -> Result<Vec<String>>
Arguments up to (but not including) the command itself.
Sourcepub async fn preflight(&self, workspace: &Path) -> Result<()>
pub async fn preflight(&self, workspace: &Path) -> Result<()>
Prove the sandbox actually works, by running something through it.
Called once at startup rather than on the first tool call, so a misconfiguration is a clear message at launch instead of a confusing tool error twenty turns into a run.