Python SDK for Sandforge hypervisor sandbox platform
Project description
Sandforge Python SDK
The Sandforge Python SDK provides a client library for interacting with the Sandforge hypervisor sandbox platform. It enables you to create, manage, and execute commands in isolated sandboxes programmatically.
Installation
Install the SDK from the repository:
pip install -e .
Or with development dependencies:
pip install -e ".[dev]"
Quick Start
Basic Usage
from sandforge import Client, SandboxSpec
# Create a client pointing to your Sandforge control plane
client = Client("http://localhost:8080")
# Create a sandbox with default configuration
sandbox = client.create_sandbox()
# Run a command
result = sandbox.commands.run(["echo", "Hello, Sandforge!"])
print(result.stdout) # "Hello, Sandforge!\n"
# Clean up
sandbox.kill()
Custom Sandbox Configuration
from sandforge import Client, SandboxSpec, WorkspaceMount
spec = SandboxSpec(
cpu=4,
memory_mb=2048,
disk_gb=20,
timeout_sec=3600,
network_mode="fetch", # Allow package downloads
mounts=[
WorkspaceMount(
host_path="/path/to/project",
guest_path="/workspace",
read_only=False,
),
],
)
client = Client("http://localhost:8080")
sandbox = client.create_sandbox(spec)
# Work with the mounted directory
result = sandbox.commands.run(["ls", "-la", "/workspace"])
print(result.stdout)
sandbox.kill()
Command Execution with Environment Variables
from sandforge import Client
client = Client("http://localhost:8080")
sandbox = client.create_sandbox()
# Run with custom environment variables
result = sandbox.commands.run(
command=["python", "-c", "import os; print(os.environ.get('MY_VAR'))"],
cwd="/",
env={"MY_VAR": "Hello World"},
timeout_sec=30,
)
print(result.stdout) # "Hello World\n"
print(result.exit_code) # 0
sandbox.kill()
Error Handling
from sandforge import Client, NetworkError, SandboxNotFoundError
client = Client("http://localhost:8080")
try:
sandbox = client.create_sandbox()
result = sandbox.commands.run(["false"]) # Command that fails
if result.exit_code != 0:
print(f"Command failed with exit code {result.exit_code}")
print(f"stderr: {result.stderr}")
sandbox.kill()
except NetworkError as e:
print(f"Connection error: {e}")
except SandboxNotFoundError as e:
print(f"Sandbox not found: {e}")
Sandbox Information
from sandforge import Client
client = Client("http://localhost:8080")
sandbox = client.create_sandbox()
# Get sandbox information
info = sandbox.info()
print(f"Sandbox ID: {info.id}")
print(f"State: {info.state}") # "ready", "executing", "destroyed", etc.
API Reference
Client
The main entry point for interacting with Sandforge.
Constructor
Client(base_url: str, timeout: int = 60)
base_url: The control plane URL (e.g., "http://localhost:8080")timeout: Request timeout in seconds (default: 60)
Methods
create_sandbox(spec: Optional[SandboxSpec] = None) -> SandboxHandle
Create a new sandbox.
- Returns: A
SandboxHandleto the created sandbox - Raises:
NetworkErrororSandforgeException
exec(sandbox_id: str, request: ExecRequest) -> ExecResult
Execute a command in a sandbox.
- Returns: An
ExecResultwith exit code, stdout, and stderr - Raises:
NetworkErrororSandforgeException
get_status(sandbox_id: str) -> str
Get the current state of a sandbox.
- Returns: The sandbox state as a string
- Raises:
NetworkError
get_info(sandbox_id: str) -> SandboxInfo
Get detailed information about a sandbox.
- Returns: A
SandboxInfoobject - Raises:
NetworkError
destroy(sandbox_id: str) -> None
Destroy a sandbox.
- Raises:
NetworkErrororSandforgeException
SandboxHandle
A handle to a created sandbox with convenience APIs.
Properties
id: The sandbox ID (string)
Methods
kill() -> None
Destroy the sandbox.
sandbox.kill()
info() -> SandboxInfo
Get sandbox information.
info = sandbox.info()
Nested APIs
commands
The CommandsAPI for executing commands.
run(command, cwd="/", env=None, timeout_sec=60) -> ExecResult
Run a command in the sandbox.
command: List of command and argumentscwd: Working directory (default: "/")env: Dictionary of environment variables (default: {})timeout_sec: Command timeout in seconds (default: 60)- Returns:
ExecResultwith exit code, stdout, and stderr
result = sandbox.commands.run(
["python", "script.py"],
cwd="/workspace",
env={"PYTHONUNBUFFERED": "1"},
timeout_sec=300,
)
files
The FilesAPI for reading files from the sandbox.
read(path: str) -> str
Read a file from the sandbox.
Note: This method is currently not implemented and raises NotImplementedError. VSOCK copyout support is coming soon.
try:
content = sandbox.files.read("/etc/hostname")
except NotImplementedError:
print("files.read() not yet supported")
Types
SandboxSpec
Specification for creating a sandbox.
SandboxSpec(
backend: str = "macos-vz", # "linux-kvm", "linux-firecracker", "macos-vz"
cpu: int = 2, # Number of vCPUs
memory_mb: int = 512, # Memory in MB
disk_gb: int = 10, # Disk size in GB
timeout_sec: int = 3600, # Sandbox lifetime in seconds
network_mode: str = "offline", # "offline", "fetch", "full"
task_isolation: str = "container", # "container", "process"
mounts: List[WorkspaceMount] = [], # Mounted directories
)
WorkspaceMount
A directory mount from host to guest.
WorkspaceMount(
host_path: str, # Path on the host
guest_path: str, # Path in the sandbox
read_only: bool = False, # Whether the mount is read-only
)
ExecRequest
A request to execute a command.
ExecRequest(
command: List[str], # Command and arguments
cwd: str = "/", # Working directory
env: Dict[str, str] = {}, # Environment variables
timeout_sec: int = 60, # Timeout in seconds
)
ExecResult
The result of command execution.
ExecResult(
exit_code: int, # Command exit code
stdout: str, # Standard output
stderr: str, # Standard error
artifacts: List[str] = [], # Paths to generated artifacts
)
SandboxInfo
Information about a sandbox.
SandboxInfo(
id: str, # Sandbox ID
state: str, # Current state (e.g., "ready", "executing", "destroyed")
)
Exceptions
All exceptions inherit from SandforgeException.
- SandforgeException: Base exception for all Sandforge errors
- NetworkError: Network communication error with the control plane
- SandboxNotFoundError: Sandbox does not exist
- ExecutionError: Command execution failed
- InvalidSpecError: Invalid sandbox specification
Error Handling
The SDK provides specific exception types for different error scenarios:
from sandforge import Client, NetworkError, SandboxNotFoundError, SandforgeException
client = Client("http://localhost:8080")
try:
sandbox = client.create_sandbox()
result = sandbox.commands.run(["exit", "1"])
except NetworkError as e:
print(f"Network error: {e}")
except SandboxNotFoundError as e:
print(f"Sandbox not found: {e}")
except SandforgeException as e:
print(f"Sandforge error: {e}")
Running Tests
pip install -e ".[dev]"
pytest tests/
Contributing
Contributions are welcome! Please ensure code passes linting and type checks:
black sandforge/
flake8 sandforge/
mypy sandforge/
License
Apache License 2.0. See LICENSE in the repository root for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sandforge_sdk-0.1.1.tar.gz.
File metadata
- Download URL: sandforge_sdk-0.1.1.tar.gz
- Upload date:
- Size: 13.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e109627090e35643518678f1502ca42b187e9b17a6cdbe812431536c51fa1a84
|
|
| MD5 |
a52fb9ea3f17fe1a1611b1370badeb94
|
|
| BLAKE2b-256 |
fc77a284ec2d55a1f53d57429ad276cf9217b3af4ee6c7f7c5bf7d4c456bdf7c
|
File details
Details for the file sandforge_sdk-0.1.1-py3-none-any.whl.
File metadata
- Download URL: sandforge_sdk-0.1.1-py3-none-any.whl
- Upload date:
- Size: 12.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5b1f3eed9e0398623f401f4463d888d035d2dadab74fe07fb78038058e5845b
|
|
| MD5 |
d7ff6b8581140c707661b3451c3fcce3
|
|
| BLAKE2b-256 |
5b3d043b7c48aa36719528b1f73eceb2febeed1a3f8114da05a7a5086d795f7f
|