Add credentialed E2B and Modal extensions, burst routing fallback, fin-hub meter export hook, BYOK docs, and 77 tests.
3.3 KiB
Extension SDK
Author guide for sand-boxer backend adapters. Version 0.1 — SAND-WP-0005.
Contract
Every extension implements three methods:
provision(profile, inputs, host) → handle dict
wait_ready(handle) → reachability dict
teardown(handle) → cleanup report dict
Optional (SaaS): estimate_cost(profile, duration) → MeterQuote
Optional (checkpoints): supports_snapshots(), snapshot(handle),
restore_from_snapshot(profile, snapshot_meta, inputs, host)
Base class
from sandboxer.extensions.base import SandboxExtension
class MyExtension(SandboxExtension):
def provision(self, profile, inputs, host): ...
def wait_ready(self, handle): ...
def teardown(self, handle): ...
Reference implementations:
| Extension | Module | Mode |
|---|---|---|
ext.compose-ssh |
compose_ssh.py |
Remote compose stack + tar snapshots |
ext.vm-packer |
vm_packer.py |
Attach workspace on pre-built VM |
ext.saas-stub |
saas_stub.py |
Metered stub + metadata snapshots |
ext.e2b |
e2b.py |
E2B cloud adapter |
ext.modal |
modal.py |
Modal cloud adapter |
Registration
- Add
extensions/ext.<name>.yaml:
id: ext.my-backend
title: My Backend
handler: sandboxer.extensions.my_backend:MyExtension
capabilities:
isolation_levels: [container]
pricing_model: self-hosted
config:
key: value
- Add a profile binding in
profiles/profile.<slug>.yamlwithextension: ext.my-backend. - Register capability metadata in
registry/when ready for reuse-surface.
Loader validates capabilities.isolation_levels and capabilities.pricing_model
at startup (sandboxer.extensions.registry).
Handle and reachability
Handle (returned by provision, stored in manager): opaque dict passed to
wait_ready and teardown. Include at minimum:
sandbox_idhost(placement host)- Fields your extension needs for SSH/API (e.g.
remote_dir,vm_target)
Reachability (returned by wait_ready): exposed on SandboxStatus.reachability:
ssh— SSH destination stringremote_dir— workspace path on remotehost— placement hostcompose_project— compose-ssh only
Inputs convention
Profiles declare semantics; extensions validate required inputs keys:
| Extension | Required inputs | Optional |
|---|---|---|
| compose-ssh | repo |
sandbox_id |
| vm-packer | vm or ssh_target |
repo, tunnel_port, ssh_port, workspace_dir |
Consumer attribution travels on SandboxCreateRequest.consumer, not extension inputs.
Testing
Mock SSH/subprocess in unit tests. See tests/test_compose_ssh.py, tests/test_vm_packer.py.
Pattern:
with patch.object(SSHConfig, "run", return_value=(0, "ready")):
ext = VMPackerExtension()
handle = ext.provision(profile, {"vm": "haskell-build"}, "localhost")
Metered extensions (SAND-WP-0006)
Implement estimate_cost and meter_actual on SandboxExtension. Register with
pricing_model: metered. See docs/payments.md and ext.saas-stub.
Deferred
| Feature | Workplan |
|---|---|
Packer build orchestration from create |
Future WP |
| Daytona OSS cloud adapter | Future WP |
| fin-hub billing export | Future |
| Cross-host snapshot transfer | Future |