feat(sandbox-morph): Morph Cloud sandbox provider worker (Infinibranch)#94
feat(sandbox-morph): Morph Cloud sandbox provider worker (Infinibranch)#94rohitg00 wants to merge 7 commits into
Conversation
Mirrors the sandbox::e2b::* ABI under sandbox::morph::*, plus registers sandbox::morph::branch — the Infinibranch primitive that returns N sibling sandbox_ids from a running parent, preserving live process state. Capabilities advertised: branch, snapshot, expose_port. fs::read/write deferred for v0 (Morph FS ops are SSH-shaped; revisit when the family agrees on a channel-vs-SSH bridge). Auth header: Authorization: Bearer MORPH_API_KEY. Default base URL: https://cloud.morph.so/api. Tests pass; clippy clean; fmt clean. HTTP bodies stubbed pending verified pass against Morph REST. A latency benchmark (target <300ms p99 for branch) lands in a follow-up commit before the wedge feature is declared stable.
Same structural fix as sandbox-daytona: - `do_list` reconciles in_flight against the upstream count when the client succeeds; falls back to the local counter on Err. Response gains a `reconciled` boolean. - `SandboxRecord.started_at` switches to a pass-through RFC3339 string to match the e2b/daytona shape. Adds three branch tests that ride along with the port: missing sandbox_id rejection, count == 0 rejection, and stub pass-through. These pin the input contract for sandbox::morph::branch ahead of the live REST wiring; when MORPH_API_KEY lands, only the client body changes. 8/8 tests pass; clippy clean; fmt clean. Live REST wiring deferred pending Morph credentials.
Replaces the stubbed /sandboxes paths with the actual Morph Cloud
surface verified through context7's mirror of cloud.morph.so/docs:
- create: POST /api/instance?snapshot_id=<image> body {metadata, ttl_seconds, ttl_action}
- exec: POST /api/instance/{id}/exec body {command: [argv]}
- stop: POST /api/instance/{id}/stop (404/409 = idempotent success)
- list: GET /api/instance response: array of {id, status, refs:{snapshot_id}, ...}
- snapshot:POST /api/instance/{id}/snapshot
- branch: POST /api/instance/{id}/branch?count=N body {snapshot_metadata, instance_metadata}
Caller's `image` field is treated as Morph's `snapshot_id` query
parameter — Morph is snapshot-first, there is no default rootfs to
fall back on, so empty image is rejected upfront with a BadInput
error rather than letting the upstream return a confusing 4xx.
`expose_port` and `fs::read/write` remain stubbed: Morph routes
those through `expose_http_service` and SSH respectively, neither of
which has a clean REST equivalent in the public docs. The worker no
longer advertises `fs` capability so callers see the supported set
correctly via capability negotiation.
15 wiremock-backed integration tests cover happy create, allowlist +
empty-image rejection, 401/5xx mapping, exec command-array shape, 404
and 409 idempotent stop, list reconciliation, list fallback, branch
sibling-id extraction, branch count=0 rejection, and snapshot id
return. Clippy + fmt clean.
… engine Verified the register_function/register_function_with handler signatures are unchanged between 0.11.3 and 0.11.6 (handler closure stays `Fn(R) -> Result<O,E>` — single-arg, no engine-supplied ctx; our HandlerCtx is captured by the closure, not an SDK parameter). All wiremock tests still pass. Pin moves to whatever the engine actually ships.
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (9)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Stops shadowing the bare sandbox::* namespace. Routes through the sandbox router worker (provider="morph"); direct invocation stays supported and stable. Handler logic, tests, S-code mapping (branch capability) unchanged.
|
Refactored to register only Validation: |
Member of the sandbox worker family. Read
sandbox-CONTEXT.md(lands via #92) for family terminology and ABI contract.What ships
sandbox-morph/— narrow Rust iii worker wrapping Morph Cloud. Morph's wedge is Infinibranch: snapshot a running VM and branch it into N siblings with live process state preserved. This is the only worker in the family that registerssandbox::*::branch.Functions
REST endpoint paths verified via context7 against
cloud.morph.so/docs/api-reference/*:sandbox::morph::createPOST /api/instance?snapshot_id=<image>body{metadata, ttl_seconds, ttl_action}sandbox::morph::execPOST /api/instance/{id}/execbody{command: [argv]}sandbox::morph::stopPOST /api/instance/{id}/stop; 404 / 409 = idempotent successsandbox::morph::listGET /api/instance; reconcilesin_flightsandbox::morph::snapshotPOST /api/instance/{id}/snapshotsandbox::morph::branchPOST /api/instance/{id}/branch?count=Nbody{snapshot_metadata, instance_metadata}sandbox::morph::expose_portexpose_http_servicelacks a clean REST equivalent todaysandbox::morph::fs::*Capabilities advertised:
["branch","snapshot","expose_port"]. Nofs.Caller contract caveat
Morph requires a
snapshot_idquery parameter on create — there's no default rootfs to fall back on. The worker rejects emptyimageupfront withWorkerError::BadInputrather than letting the upstream return a confusing 4xx.Tests
15 wiremock-backed cases including the branch happy-path (returns
{sandbox_ids: [...]}from Morph'sinstances:[{id}, {id}]response),count: 0rejection, snapshot-id extraction, 401 → S503, 5xx rollback, list reconciliation. Clippy clean (withdoc_markdownallowed for URL-shaped doc comments).Live test status
Wired against documented shapes; not yet run end-to-end (no
MORPH_API_KEYavailable during this PR's authoring). Pattern-matches the e2b/daytona fix cycle that was live-verified.Pin
iii-sdk = "=0.11.6".