--- id: SAND-WP-0010 type: workplan title: "Cloud adapters and billing export" domain: infotech repo: sand-boxer status: ready owner: codex topic_slug: custodian created: "2026-06-24" updated: "2026-06-24" state_hub_workstream_id: "a78ea9f1-d076-43a6-8798-36fc333edd25" --- # Cloud adapters and billing export Replace `ext.saas-stub` with real metered cloud backends (E2B, Modal) and wire BYOK credential routing plus fin-hub billing export. Gap analysis P5/P10: `history/2026-06-24-post-wp0007-intent-scope-gap-analysis.md` Carries forward: SAND-WP-0006-T06 (deferred) **Predecessor:** SAND-WP-0009 (TTL — finished) **Follow-on:** SAND-WP-0011 (reachability + consumer profiles) --- ## Credential routing and BYOK ```task id: SAND-WP-0010-T01 status: todo priority: high state_hub_task_id: "5aeb6a17-dc5b-4e39-996c-f7f31c2659f4" ``` Document provider key paths via `warden route find` (OpenBao custody — never in Git). Extension config `secret_ref` fields; loader resolves at provision time into env/handle only (not persisted on `SandboxStatus`). Docs: `docs/payments.md` BYOK section. ## ext.e2b adapter ```task id: SAND-WP-0010-T02 status: todo priority: high state_hub_task_id: "205bc70a-aaa6-4cd7-b0a5-11669490c150" ``` `extensions/ext.e2b.yaml`, `sandboxer.extensions.e2b:E2BExtension` — provision, `wait_ready`, `teardown`, `estimate_cost`, `meter_actual`. Profile `profile.e2b-burst` with `pricing_model: metered`. Unit tests with mocked HTTP client (no live API in CI). ## ext.modal adapter ```task id: SAND-WP-0010-T03 status: todo priority: high state_hub_task_id: "b9f104e1-e9d6-4324-b82a-8406be3006e5" ``` `extensions/ext.modal.yaml`, `sandboxer.extensions.modal:ModalExtension` — same contract as E2B. Profile `profile.modal-gpu` (or shared burst profile with routing). Mocked tests. ## Routing and credits integration ```task id: SAND-WP-0010-T04 status: todo priority: high state_hub_task_id: "c11bdaf1-4c25-4c14-a566-0e28b0bd8b1d" ``` Update `profile.burst-sandbox` route list to prefer real adapters when credentials present; fall back to `ext.saas-stub`. Pre-create balance check and post-destroy debit unchanged. Emit meter events with `extension_id` discriminator. ## fin-hub billing export ```task id: SAND-WP-0010-T05 status: todo priority: medium state_hub_task_id: "4eb1b0df-c6d7-4fb6-a7a4-e1455d2fac61" ``` On metered destroy, optional export hook (`SANDBOXER_FIN_HUB_URL` or disabled by default) posting usage record (sandbox_id, extension_id, duration_s, actual_usd). Stub/mock in tests; operator runbook for railiance-platform path. ## Docs and capability registry ```task id: SAND-WP-0010-T06 status: todo priority: medium state_hub_task_id: "d0aba132-b8fa-461b-b722-099868bf1770" ``` `docs/cloud-adapters.md`, runbook per provider, registry maturity bump (A5/C5 when adapters ship). Update `SCOPE.md`, `docs/routing.md`. ## Tests and smoke ```task id: SAND-WP-0010-T07 status: todo priority: high state_hub_task_id: "3aebb3be-ae5e-4642-9710-9d80a1e8a582" ``` `tests/test_e2b.py`, `tests/test_modal.py`, routing fallback tests. Optional operator smoke script (gated on credentials, not CI). `make check` green. --- ## Out of scope | Item | Track | |------|-------| | Coulomb-native runtime (phase 5) | Backlog | | Daytona OSS adapter | Future WP | | Cross-host snapshot transfer | Future | --- ## Acceptance criteria - At least one real cloud adapter provisions/teardown via CLI with mocked CI - BYOK documented; no secrets in repo or State Hub payloads - `profile.burst-sandbox` routes to real adapter when creds available - fin-hub export hook callable (stub OK in v0) - SAND-WP-0006-T06 superseded; cancel or mark done when complete