feat: snapshot/restore checkpoints (SAND-WP-0007)

Add workspace checkpoint API with SnapshotStore, extension hooks on
compose-ssh and saas-stub, manager orchestration, CLI/HTTP surface,
profile.compose-checkpoint, and docs/tests.
This commit is contained in:
2026-06-24 07:57:40 +02:00
parent 2760ef2373
commit 952cebf2e9
21 changed files with 966 additions and 34 deletions

View File

@@ -12,7 +12,10 @@ wait_ready(handle) → reachability dict
teardown(handle) → cleanup report dict
```
Optional (SaaS, deferred): `estimate_cost(profile, duration) → MeterQuote`
Optional (SaaS): `estimate_cost(profile, duration) → MeterQuote`
Optional (checkpoints): `supports_snapshots()`, `snapshot(handle)`,
`restore_from_snapshot(profile, snapshot_meta, inputs, host)`
### Base class
@@ -29,8 +32,9 @@ Reference implementations:
| Extension | Module | Mode |
|-----------|--------|------|
| `ext.compose-ssh` | `compose_ssh.py` | Remote compose stack |
| `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 |
## Registration
@@ -104,4 +108,4 @@ Implement `estimate_cost` and `meter_actual` on `SandboxExtension`. Register wit
| Packer build orchestration from `create` | Future WP |
| E2B / Modal / Daytona cloud adapters | Post SAND-WP-0006 |
| fin-hub billing export | Future |
| Snapshot / restore hooks | SAND-WP-0007 |
| Cross-host snapshot transfer | Future |

View File

@@ -16,7 +16,7 @@ agent harnessing, validation, and code generation.
| **Extension** | Backend adapter implementing provision / wait_ready / teardown |
| **Host** | Registered placement target for self-hosted extensions; read-only telemetry via `profile.sandbox-canary` (see `docs/host-telemetry.md`) |
| **Sandbox** | Running instance of a profile |
| **Snapshot** | Point-in-time workspace checkpoint (deferred — SAND-WP-0003) |
| **Snapshot** | Point-in-time workspace checkpoint (`sandboxer snapshot` / `restore`) |
| **Route** | Extension selection policy when multiple backends qualify |
| **Meter** | Usage record for payments layer (SaaS extensions — SAND-WP-0006) |
@@ -85,7 +85,7 @@ Extends the `build-agent` self-register pattern: generic sandbox identities carr
| `extend_ttl` | Extend time-to-live | Stub |
| `recreate` | Destroy and reprovision from stored seed | **Yes** |
| `destroy` | Idempotent teardown | **Yes** |
| `snapshot` / `restore` | Checkpoint workspace | Deferred (SAND-WP-0003) |
| `snapshot` / `restore` | Checkpoint workspace | **Yes** (compose-ssh, saas-stub) |
| `exec` | Run command in sandbox | Harness-owned via SSH (glas-harness) |
HTTP surface (optional v0; CLI calls core library directly):
@@ -94,6 +94,9 @@ HTTP surface (optional v0; CLI calls core library directly):
- `GET /v1/sandboxes/{id}` — get
- `GET /v1/sandboxes` — list
- `DELETE /v1/sandboxes/{id}` — destroy
- `POST /v1/sandboxes/{id}/snapshot` — checkpoint
- `POST /v1/snapshots/{id}/restore` — restore
- `GET /v1/snapshots` — list checkpoints
---

View File

@@ -45,5 +45,5 @@ Deferred: Packer orchestration from API, `make remote-build` shim.
|------|----------|
| ~~SaaS extensions + payments v0~~ | SAND-WP-0006 — stub + routing + credits |
| E2B / Modal real adapters | Post SAND-WP-0006 |
| Snapshot / restore | SAND-WP-0007 |
| ~~Snapshot / restore~~ | SAND-WP-0007`docs/snapshots.md` |
| TTL enforcement + scheduled reap | TBD |

47
docs/snapshots.md Normal file
View File

@@ -0,0 +1,47 @@
# Workspace snapshots
Point-in-time workspace checkpoints — SAND-WP-0007.
## Overview
Snapshots capture the remote workspace state of a **ready** sandbox without
destroying it. Restore provisions a **new** sandbox from the checkpoint.
| Operation | CLI | HTTP |
|-----------|-----|------|
| Create checkpoint | `sandboxer snapshot <sandbox_id>` | `POST /v1/sandboxes/{id}/snapshot` |
| Restore | `sandboxer restore <snapshot_id>` | `POST /v1/snapshots/{id}/restore` |
| List | `sandboxer snapshots list` | `GET /v1/snapshots` |
| Get | `sandboxer snapshots get <id>` | `GET /v1/snapshots/{id}` |
Snapshot metadata is stored at `~/.local/share/sandboxer/snapshots.json`.
Extension artifacts (e.g. tarballs) live on the placement host.
## Profile
`profile.compose-checkpoint` binds `ext.compose-ssh` for checkpoint-enabled
compose sandboxes. Use the same `inputs.repo` convention as `profile.compose-e2e`.
## ext.compose-ssh behavior
1. **Snapshot**`tar czf` of `remote_dir` to `{base_dir}/snapshots/{id}.tar.gz`
2. **Restore** — new `sandbox_id`, extract tarball, `compose up -d`
Cross-host restore is not supported in v0 (artifact must be on the target host).
## ext.saas-stub
Metadata-only checkpoints for routing and payments tests. Restore reprovisions
a fresh stub endpoint.
## Extension contract
Optional hooks on `SandboxExtension`:
```python
def supports_snapshots(self) -> bool: ...
def snapshot(self, handle) -> dict[str, str]: ...
def restore_from_snapshot(self, profile, snapshot_meta, inputs, host) -> dict[str, str]: ...
```
See `docs/extension-sdk.md`.