generated from coulomb/repo-seed
Add SandboxExtension base class, extension SDK docs, vm-packer attach mode for build-machines VMs, profile.vm-haskell-build, SSH port support, tests, and migration docs.
102 lines
2.8 KiB
Markdown
102 lines
2.8 KiB
Markdown
# Extension SDK
|
|
|
|
Author guide for sand-boxer backend adapters. Version 0.1 — SAND-WP-0005.
|
|
|
|
## Contract
|
|
|
|
Every extension implements three methods:
|
|
|
|
```text
|
|
provision(profile, inputs, host) → handle dict
|
|
wait_ready(handle) → reachability dict
|
|
teardown(handle) → cleanup report dict
|
|
```
|
|
|
|
Optional (SaaS, deferred): `estimate_cost(profile, duration) → MeterQuote`
|
|
|
|
### Base class
|
|
|
|
```python
|
|
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 |
|
|
| `ext.vm-packer` | `vm_packer.py` | Attach workspace on pre-built VM |
|
|
|
|
## Registration
|
|
|
|
1. Add `extensions/ext.<name>.yaml`:
|
|
|
|
```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
|
|
```
|
|
|
|
2. Add a profile binding in `profiles/profile.<slug>.yaml` with `extension: ext.my-backend`.
|
|
3. 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_id`
|
|
- `host` (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 string
|
|
- `remote_dir` — workspace path on remote
|
|
- `host` — placement host
|
|
- `compose_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:
|
|
|
|
```python
|
|
with patch.object(SSHConfig, "run", return_value=(0, "ready")):
|
|
ext = VMPackerExtension()
|
|
handle = ext.provision(profile, {"vm": "haskell-build"}, "localhost")
|
|
```
|
|
|
|
## Deferred
|
|
|
|
| Feature | Workplan |
|
|
|---------|----------|
|
|
| Packer build orchestration from `create` | Future WP |
|
|
| SaaS adapters + `estimate_cost` | SAND-WP-0006 |
|
|
| Multi-backend routing engine | SAND-WP-0006 |
|
|
| Snapshot / restore hooks | SAND-WP-0007 | |