Skip to main content

Crate bashkit

Crate bashkit 

Source
Expand description

BashKit - Sandboxed bash interpreter for multi-tenant environments

BashKit provides a fully sandboxed bash interpreter with a virtual filesystem, making it safe to execute untrusted scripts in multi-tenant environments like AI agents, CI/CD pipelines, and code sandboxes.

§Features

  • Virtual Filesystem: All file operations happen in memory by default
  • Resource Limits: Control command count, loop iterations, and function depth
  • Sandboxed Identity: Customizable username/hostname for whoami, hostname, etc.
  • Custom Builtins: Extend with domain-specific commands (psql, kubectl, etc.)
  • 30+ Built-in Commands: echo, cat, grep, sed, awk, jq, and more
  • Full Bash Syntax: Variables, pipelines, redirects, loops, functions, arrays

§Quick Start

use bashkit::Bash;

let mut bash = Bash::new();
let result = bash.exec("echo 'Hello, World!'").await?;
assert_eq!(result.stdout, "Hello, World!\n");
assert_eq!(result.exit_code, 0);

§Basic Usage

§Simple Commands

use bashkit::Bash;

let mut bash = Bash::new();

// Echo with variables
let result = bash.exec("NAME=World; echo \"Hello, $NAME!\"").await?;
assert_eq!(result.stdout, "Hello, World!\n");

// Pipelines
let result = bash.exec("echo -e 'apple\\nbanana\\ncherry' | grep a").await?;
assert_eq!(result.stdout, "apple\nbanana\n");

// Arithmetic
let result = bash.exec("echo $((2 + 2 * 3))").await?;
assert_eq!(result.stdout, "8\n");

§Control Flow

use bashkit::Bash;

let mut bash = Bash::new();

// For loops
let result = bash.exec("for i in 1 2 3; do echo $i; done").await?;
assert_eq!(result.stdout, "1\n2\n3\n");

// If statements
let result = bash.exec("if [ 5 -gt 3 ]; then echo bigger; fi").await?;
assert_eq!(result.stdout, "bigger\n");

// Functions
let result = bash.exec("greet() { echo \"Hello, $1!\"; }; greet World").await?;
assert_eq!(result.stdout, "Hello, World!\n");

§File Operations

All file operations happen in the virtual filesystem:

use bashkit::Bash;

let mut bash = Bash::new();

// Create and read files
bash.exec("echo 'Hello' > /tmp/test.txt").await?;
bash.exec("echo 'World' >> /tmp/test.txt").await?;

let result = bash.exec("cat /tmp/test.txt").await?;
assert_eq!(result.stdout, "Hello\nWorld\n");

// Directory operations
bash.exec("mkdir -p /data/nested/dir").await?;
bash.exec("echo 'content' > /data/nested/dir/file.txt").await?;

§Configuration with Builder

Use Bash::builder() for advanced configuration:

use bashkit::{Bash, ExecutionLimits};

let mut bash = Bash::builder()
    .env("API_KEY", "secret123")
    .username("deploy")
    .hostname("prod-server")
    .limits(ExecutionLimits::new().max_commands(100))
    .build();

let result = bash.exec("whoami && hostname").await?;
assert_eq!(result.stdout, "deploy\nprod-server\n");

§Custom Builtins

Register custom commands to extend BashKit with domain-specific functionality:

use bashkit::{Bash, Builtin, BuiltinContext, ExecResult, async_trait};

struct Greet;

#[async_trait]
impl Builtin for Greet {
    async fn execute(&self, ctx: BuiltinContext<'_>) -> bashkit::Result<ExecResult> {
        let name = ctx.args.first().map(|s| s.as_str()).unwrap_or("World");
        Ok(ExecResult::ok(format!("Hello, {}!\n", name)))
    }
}

let mut bash = Bash::builder()
    .builtin("greet", Box::new(Greet))
    .build();

let result = bash.exec("greet Alice").await?;
assert_eq!(result.stdout, "Hello, Alice!\n");

Custom builtins have access to:

  • Command arguments (ctx.args)
  • Environment variables (ctx.env)
  • Shell variables (ctx.variables)
  • Virtual filesystem (ctx.fs)
  • Pipeline stdin (ctx.stdin)

See BashBuilder::builtin for more details.

§Virtual Filesystem

BashKit provides three filesystem implementations:

  • InMemoryFs: Simple in-memory filesystem (default)
  • OverlayFs: Copy-on-write overlay for layered storage
  • MountableFs: Mount multiple filesystems at different paths

See the fs module documentation for details and examples.

§Direct Filesystem Access

Access the filesystem directly via Bash::fs():

use bashkit::{Bash, FileSystem};
use std::path::Path;

let mut bash = Bash::new();
let fs = bash.fs();

// Pre-populate files before running scripts
fs.mkdir(Path::new("/config"), false).await?;
fs.write_file(Path::new("/config/app.conf"), b"debug=true").await?;

// Run a script that reads the config
let result = bash.exec("cat /config/app.conf").await?;
assert_eq!(result.stdout, "debug=true");

// Read script output directly
bash.exec("echo 'result' > /output.txt").await?;
let output = fs.read_file(Path::new("/output.txt")).await?;
assert_eq!(output, b"result\n");

§Examples

See the examples/ directory for complete working examples:

  • basic.rs - Getting started with BashKit
  • custom_fs.rs - Using different filesystem implementations
  • custom_filesystem_impl.rs - Implementing the FileSystem trait
  • resource_limits.rs - Setting execution limits
  • sandbox_identity.rs - Customizing username/hostname
  • text_processing.rs - Using grep, sed, awk, and jq
  • agent_tool.rs - LLM agent integration

§Guides

Modules§

compatibility_guide
Comprehensive reference for supported bash features.
custom_builtins_guide
Guide for creating custom builtins to extend BashKit.
parser
Parser module - exposed for fuzzing and testing Parser module for BashKit

Structs§

Bash
Main entry point for BashKit.
BashBuilder
Builder for customized Bash configuration.
BuiltinContext
Execution context for builtin commands.
DirEntry
An entry in a directory listing.
ExecResult
Result of executing a bash script.
ExecutionCounters
Execution counters for tracking resource usage
ExecutionLimits
Resource limits for script execution
InMemoryFs
In-memory filesystem implementation.
Metadata
File or directory metadata.
MountableFs
Filesystem with Unix-style mount points.
NetworkAllowlist
Network allowlist configuration.
OverlayFs
Copy-on-write overlay filesystem.

Enums§

ControlFlow
Control flow signals from commands like break, continue, return
Error
BashKit error types.
FileType
Type of a filesystem entry.
LimitExceeded
Error returned when a resource limit is exceeded

Traits§

Builtin
Trait for implementing builtin commands.
FileSystem
Async virtual filesystem trait.

Type Aliases§

Result
Result type alias using BashKit’s Error.

Attribute Macros§

async_trait