generated from coulomb/repo-seed
feat: cloud adapters E2B/Modal and billing export (SAND-WP-0010)
Add credentialed E2B and Modal extensions, burst routing fallback, fin-hub meter export hook, BYOK docs, and 77 tests.
This commit is contained in:
54
docs/cloud-adapters.md
Normal file
54
docs/cloud-adapters.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Cloud adapters (E2B, Modal)
|
||||
|
||||
Metered SaaS sandbox backends — SAND-WP-0010.
|
||||
|
||||
## Extensions
|
||||
|
||||
| Extension | Profile | Provider API |
|
||||
|-----------|---------|--------------|
|
||||
| `ext.e2b` | `profile.e2b-burst` | `https://api.e2b.dev` |
|
||||
| `ext.modal` | `profile.modal-gpu` | `https://api.modal.com` |
|
||||
| `ext.saas-stub` | `profile.saas-stub` | None (local stub) |
|
||||
|
||||
`profile.burst-sandbox` routes: compose-ssh → E2B → Modal → saas-stub.
|
||||
|
||||
## BYOK credentials
|
||||
|
||||
Resolve keys at provision boundary only — never in Git, workplans, or State Hub.
|
||||
|
||||
```bash
|
||||
warden route find "E2B API key" --json
|
||||
warden route find "Modal token" --json
|
||||
```
|
||||
|
||||
| Extension | Primary env | secret_ref env fallback |
|
||||
|-----------|-------------|-------------------------|
|
||||
| `ext.e2b` | `E2B_API_KEY` | `SANDBOXER_SECRET_E2B_API_KEY` |
|
||||
| `ext.modal` | `MODAL_TOKEN_ID` | `SANDBOXER_SECRET_MODAL_TOKEN_ID` |
|
||||
|
||||
OpenBao custody via railiance-platform; sand-boxer reads env injected by operator.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
export E2B_API_KEY=... # operator-injected, not in repo
|
||||
|
||||
sandboxer create --profile profile.e2b-burst
|
||||
sandboxer create --profile profile.burst-sandbox # SaaS when self-hosted unavailable
|
||||
sandboxer destroy <id>
|
||||
```
|
||||
|
||||
## fin-hub export
|
||||
|
||||
On metered destroy, optional POST to `SANDBOXER_FIN_HUB_URL/usage/sandbox`.
|
||||
Disabled by default. Set `SANDBOXER_NO_FIN_HUB=1` to suppress.
|
||||
|
||||
## CI
|
||||
|
||||
Unit tests mock HTTP — no live provider calls in `make check`.
|
||||
|
||||
Operator smoke (credentials required):
|
||||
|
||||
```bash
|
||||
./scripts/smoke-cloud-adapter.sh e2b
|
||||
```
|
||||
@@ -35,6 +35,8 @@ Reference implementations:
|
||||
| `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
|
||||
|
||||
@@ -106,6 +108,6 @@ Implement `estimate_cost` and `meter_actual` on `SandboxExtension`. Register wit
|
||||
| Feature | Workplan |
|
||||
|---------|----------|
|
||||
| Packer build orchestration from `create` | Future WP |
|
||||
| E2B / Modal / Daytona cloud adapters | Post SAND-WP-0006 |
|
||||
| Daytona OSS cloud adapter | Future WP |
|
||||
| fin-hub billing export | Future |
|
||||
| Cross-host snapshot transfer | Future |
|
||||
@@ -44,7 +44,7 @@ Deferred: Packer orchestration from API, `make remote-build` shim.
|
||||
| Item | Workplan |
|
||||
|------|----------|
|
||||
| ~~SaaS extensions + payments v0~~ | SAND-WP-0006 — stub + routing + credits |
|
||||
| E2B / Modal real adapters + fin-hub | **SAND-WP-0010** |
|
||||
| ~~E2B / Modal real adapters + fin-hub~~ | SAND-WP-0010 — `docs/cloud-adapters.md` |
|
||||
| Consumer profiles + reachability | **SAND-WP-0011** |
|
||||
| Packer orchestration + remote-build shim | **SAND-WP-0012** |
|
||||
| ~~Snapshot / restore~~ | SAND-WP-0007 — `docs/snapshots.md` |
|
||||
|
||||
@@ -36,10 +36,17 @@ Reference: `ext.saas-stub` (no external API).
|
||||
|
||||
## BYOK
|
||||
|
||||
Provider API keys are resolved at provision boundary via `secret_refs` / OpenBao —
|
||||
not implemented in v0 stub. Set provider env vars per extension when adapters land.
|
||||
Provider API keys resolve at provision boundary — never stored on `SandboxStatus`
|
||||
or emitted to State Hub.
|
||||
|
||||
1. Operator lookup: `warden route find "<provider> API key" --json`
|
||||
2. Inject env before `sandboxer create` (e.g. `E2B_API_KEY`, `MODAL_TOKEN_ID`)
|
||||
3. Or map `secret_ref` from extension config to `SANDBOXER_SECRET_<REF>` env
|
||||
|
||||
See `docs/cloud-adapters.md`.
|
||||
|
||||
## Billing export
|
||||
|
||||
sand-boxer meters sandbox consumption only. Domain billing authority (fin-hub) is a
|
||||
future export consumer of State Hub meter events — not owned here.
|
||||
On metered destroy, optional fin-hub hook when `SANDBOXER_FIN_HUB_URL` is set.
|
||||
Posts `sandbox_id`, `extension_id`, `duration_s`, `actual_usd` to `/usage/sandbox`.
|
||||
Implementation: `src/sandboxer/payments/billing_export.py`.
|
||||
@@ -10,6 +10,8 @@ route:
|
||||
strategy: prefer-self-hosted
|
||||
extensions:
|
||||
- ext.compose-ssh
|
||||
- ext.e2b
|
||||
- ext.modal
|
||||
- ext.saas-stub
|
||||
max_cost_per_hour_usd: 1.0
|
||||
```
|
||||
@@ -19,7 +21,7 @@ route:
|
||||
| Strategy | Behavior |
|
||||
|----------|----------|
|
||||
| `explicit` | Use `profile.extension` (default when no route) |
|
||||
| `prefer-self-hosted` | First self-hosted candidate with resolvable host; else SaaS |
|
||||
| `prefer-self-hosted` | Self-hosted if host available; else credentialed E2B/Modal; else stub |
|
||||
| `lowest-cost` | Self-hosted if available; else cheapest `estimate_cost` |
|
||||
| `lowest-latency` | Self-hosted if available; else last candidate (v0) |
|
||||
|
||||
@@ -38,7 +40,12 @@ sandboxer create --profile profile.saas-stub
|
||||
|
||||
| Profile | Route |
|
||||
|---------|-------|
|
||||
| `profile.burst-sandbox` | compose-ssh → saas-stub fallback |
|
||||
| `profile.burst-sandbox` | compose-ssh → e2b → modal → saas-stub |
|
||||
| `profile.e2b-burst` | explicit `ext.e2b` |
|
||||
| `profile.modal-gpu` | explicit `ext.modal` |
|
||||
| `profile.saas-stub` | explicit `ext.saas-stub` |
|
||||
|
||||
Cloud adapters require provider credentials (`E2B_API_KEY`, `MODAL_TOKEN_ID`).
|
||||
See `docs/cloud-adapters.md`.
|
||||
|
||||
Resolver: `sandboxer.routing.resolver.resolve_extension`.
|
||||
Reference in New Issue
Block a user