microsandbox 0.6.2

`microsandbox` is the core library for the microsandbox project.
docs.rs failed to build microsandbox-0.6.2
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: microsandbox-0.1.2

microsandbox

Lightweight VM sandboxes for Rust applications that need hardware-level isolation for AI agents, tools, tests, and untrusted code.

microsandbox is the Rust SDK for the microsandbox runtime. It exposes an async API for creating microVM-backed sandboxes, running commands, reading and writing guest files, managing volumes, configuring network policy, and working with secrets.

For full API documentation, use the docs site and generated Rust docs:

Features

  • Hardware VM isolation with a guest Linux kernel
  • OCI image, bind-rootfs, disk-image, and snapshot-based sandboxes
  • Collected and streaming command execution
  • Guest filesystem read, write, list, copy, stat, and stream operations
  • Named volumes, bind mounts, tmpfs mounts, and disk-image mounts
  • Network policies, DNS filtering, TLS interception, secrets, and port publishing
  • Rootfs patches before boot
  • Detached sandboxes that can outlive the Rust process
  • Metrics, logs, snapshots, SSH/SFTP, image cache, and local/cloud backend helpers

Requirements

  • Rust toolchain with Rust 2024 edition support
  • Linux with KVM, macOS with Apple Silicon, or Windows with Windows Hypervisor Platform
  • Windows support is currently preview; see the Windows troubleshooting guide for WHP and runtime setup notes.

Installation

cargo add microsandbox

Cargo Features

Feature Default Description
keyring yes Registry credential lookup through the platform keyring
net yes Networking, port publishing, policies, TLS interception, and secrets
prebuilt yes Use prebuilt runtime artifacts where available
ssh no SSH, SFTP, and interactive SSH helpers

To build without the networking stack while keeping the default keyring and prebuilt-runtime behavior:

cargo add microsandbox --no-default-features --features keyring,prebuilt

Quick Start

use microsandbox::Sandbox;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let sandbox = Sandbox::builder("rust-readme")
        .image("alpine")
        .cpus(1)
        .memory(512)
        .replace()
        .create()
        .await?;

    let output = sandbox.shell("echo 'Hello from microsandbox!'").await?;
    println!("{}", output.stdout()?.trim());

    sandbox.stop().await?;
    Sandbox::remove("rust-readme").await?;

    Ok(())
}

Common Examples

These snippets assume you already have a live sandbox: Sandbox. See examples/rust for complete runnable crates.

Command Execution

use microsandbox::ExecEvent;

let output = sandbox.exec("python3", ["-c", "print(1 + 1)"]).await?;
println!("stdout: {}", output.stdout()?);
println!("exit code: {}", output.status().code);

let mut handle = sandbox.exec_stream("tail", ["-f", "/var/log/app.log"]).await?;
while let Some(event) = handle.recv().await {
    match event {
        ExecEvent::Stdout(data) => print!("{}", String::from_utf8_lossy(&data)),
        ExecEvent::Stderr(data) => eprint!("{}", String::from_utf8_lossy(&data)),
        ExecEvent::Exited { code } => {
            println!("exited with {code}");
            break;
        }
        ExecEvent::Started { .. } => {}
        ExecEvent::Failed(err) => {
            eprintln!("exec failed: {err:?}");
            break;
        }
        ExecEvent::StdinError(err) => eprintln!("stdin error: {err:?}"),
    }
}

Filesystem Operations

let fs = sandbox.fs();

fs.write("/tmp/config.json", br#"{"debug": true}"#).await?;

let data = fs.read("/tmp/config.json").await?;
println!("{}", String::from_utf8_lossy(&data));

for entry in fs.list("/etc").await? {
    println!("{} ({:?})", entry.path, entry.kind);
}

Named Volumes

use microsandbox::{Sandbox, Volume, size::SizeExt};

let data = Volume::builder("readme-data").quota(100.mib()).create().await?;

let writer = Sandbox::builder("readme-writer")
    .image("alpine")
    .volume("/data", |v| v.named(data.name()))
    .replace()
    .create()
    .await?;

writer.shell("echo 'hello' > /data/message.txt").await?;
writer.stop().await?;

let reader = Sandbox::builder("readme-reader")
    .image("alpine")
    .volume("/data", |v| v.named(data.name()).readonly())
    .replace()
    .create()
    .await?;

let output = reader.shell("cat /data/message.txt").await?;
println!("{}", output.stdout()?.trim());

Network Policies

use microsandbox::{NetworkPolicy, Sandbox};

let isolated = Sandbox::builder("readme-isolated")
    .image("alpine")
    .network(|n| n.policy(NetworkPolicy::none()))
    .replace()
    .create()
    .await?;

let filtered_policy = NetworkPolicy::builder()
    .default_allow()
    .rule(|r| r.egress().deny().domain("blocked.example.com"))
    .rule(|r| r.egress().deny().domain_suffix(".evil.com"))
    .build()?;

let filtered = Sandbox::builder("readme-filtered")
    .image("alpine")
    .network(|n| n.policy(filtered_policy))
    .replace()
    .create()
    .await?;

Use .disable_network() when the sandbox should not receive a network interface at all. Use NetworkPolicy::none() when the interface should exist but policy should deny traffic.

Port Publishing

let sandbox = Sandbox::builder("readme-web")
    .image("python")
    .port(8080, 80)
    .replace()
    .create()
    .await?;

Secrets

Secrets use placeholder substitution. The real value stays on the host and is substituted only for allowed network destinations.

let sandbox = Sandbox::builder("readme-agent")
    .image("python")
    .secret_env("OPENAI_API_KEY", "sk-real-secret-123", "api.openai.com")
    .replace()
    .create()
    .await?;

Rootfs Patches

let sandbox = Sandbox::builder("readme-patched")
    .image("alpine")
    .patch(|p| {
        p.text("/etc/greeting.txt", "Hello!\n", None, false)
            .mkdir("/app", Some(0o755))
            .append("/etc/hosts", "127.0.0.1 myapp.local\n")
    })
    .replace()
    .create()
    .await?;

Detached Mode

let sandbox = Sandbox::builder("readme-background")
    .image("python")
    .detached(true)
    .replace()
    .create()
    .await?;

sandbox.detach().await;

let handle = Sandbox::get("readme-background").await?;
let reconnected = handle.connect().await?;
let output = reconnected.shell("echo reconnected").await?;
println!("{}", output.stdout()?.trim());

More Documentation

License

Apache-2.0