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

@@ -5,7 +5,7 @@ from unittest.mock import patch
from fastapi.testclient import TestClient
from sandboxer.api.app import app
from sandboxer.models import ActorType, Consumer, SandboxState, SandboxStatus
from sandboxer.models import ActorType, Consumer, SandboxState, SandboxStatus, SnapshotRecord
def test_list_sandboxes_empty() -> None:
@@ -46,4 +46,46 @@ def test_create_sandbox() -> None:
},
)
assert resp.status_code == 200
assert resp.json()["sandbox_id"] == "abc12345"
assert resp.json()["sandbox_id"] == "abc12345"
def test_snapshot_sandbox() -> None:
from datetime import UTC, datetime
record = SnapshotRecord(
snapshot_id="snap12345678",
sandbox_id="abc12345",
profile_id="profile.compose-checkpoint",
extension_id="ext.compose-ssh",
host="coulombcore",
created_at=datetime.now(UTC),
)
with patch("sandboxer.api.app._manager") as mgr:
mgr.snapshot.return_value = record
client = TestClient(app)
resp = client.post("/v1/sandboxes/abc12345/snapshot")
assert resp.status_code == 200
assert resp.json()["snapshot_id"] == "snap12345678"
def test_restore_snapshot() -> None:
from datetime import UTC, datetime
status = SandboxStatus(
sandbox_id="restored1",
profile_id="profile.compose-checkpoint",
extension_id="ext.compose-ssh",
state=SandboxState.READY,
consumer=Consumer(actor=ActorType.ADM, project="sand-boxer"),
created_at=datetime.now(UTC),
updated_at=datetime.now(UTC),
)
with patch("sandboxer.api.app._manager") as mgr:
mgr.restore.return_value = status
client = TestClient(app)
resp = client.post(
"/v1/snapshots/snap12345678/restore",
json={"consumer": {"actor": "adm", "project": "sand-boxer"}},
)
assert resp.status_code == 200
assert resp.json()["sandbox_id"] == "restored1"