feat: add daytona sandbox provider (RFC, narrow scope)#32
feat: add daytona sandbox provider (RFC, narrow scope)#32zozo123 wants to merge 2 commits intoopenclaw:mainfrom
Conversation
fb25d89 to
24d4c7a
Compare
|
Rebased onto current main ( Local verification on this commit: CLI wiring smoke (no creds set):
Live API smoke (warmup → run → ssh → stop) requires a Happy to keep this in draft for a scope discussion, or convert to ready-for-review on your signal — your call. |
24d4c7a to
7b08d93
Compare
Live API verification completeRan the full lifecycle against the real Daytona API ( Bugs caught and fixed by the live smoke
Verified output (key + tokens scrubbed)Still user-side prerequisites (unchanged)
Quality gates on
|
|
Follow-up fixes pushed in Addressed the review blockers:
Added regression coverage for all three: coordinator bypass, official label wrapper payload, and stopped-sandbox reuse before SSH token creation. Local verification on the pushed commit: gofmt -w internal/cli/daytona.go internal/cli/daytona_test.go internal/cli/target.go
go test -count=1 ./...
go test -race -count=1 ./internal/cli/...
go vet ./...
go build -trimpath ./cmd/crabbox
git diff --checkAll passed. Scope remains unchanged: direct Daytona provider only, no Worker/coordinator, VNC, Windows/macOS, Tailscale, or CLI wrapper expansion. |
steipete
left a comment
There was a problem hiding this comment.
Thanks for the careful follow-up and the live Daytona smoke. I’m leaving this as requested changes for now because the current merge result is not narrow anymore.
I fetched GitHub’s merge ref for this PR against current main (0bb34bd) and compared the actual merge result:
git fetch origin pull/32/merge:refs/tmp/crabbox-pr-32-merge
git diff --stat main..refs/tmp/crabbox-pr-32-mergeThat merge result is 61 files changed, 1866 insertions(+), 3163 deletions(-), and it would delete or rewrite unrelated current-main code/docs, including:
D docs/commands/code.md
M docs/commands/webvnc.md
D docs/features/image-bake-runbook.md
D docs/features/prebaked-images.md
D internal/cli/code.go
M worker/src/fleet.ts
So before we can review/approve CI, please rebase onto current main and keep the diff limited to the Daytona provider surface. Expected shape is roughly the new Daytona provider + tests + provider/docs/changelog wiring, without removing the current code/webvnc/image-bake work.
I’m intentionally not approving the pending fork CI run while the merge ref has this unrelated rollback shape.
|
I did a deeper pass on the Daytona-specific code as well. Separate from the stale merge-ref/rebase blocker above, I found two things worth fixing before this should be considered ready:
if daytonaSnapshot(cfg) == "" {
return ..., exit(2, "provider=daytona requires daytona.snapshot or CRABBOX_DAYTONA_SNAPSHOT")
}Then later it only sends That means Best fix: either drop/hide the resource override surface from this first snapshot-only PR, or add the proper image/base-image creation mode with the correct request shape. I’d strongly prefer the former for this narrow PR unless we know we need image creation now.
The docs added here say the org ID is “only required for JWT auth”, and Daytona’s SDK docs say Local proof I ran on the current PR head ( go test -count=1 ./...
go vet ./...
go test -race -count=1 ./internal/cli/...
go build -trimpath ./cmd/crabboxThose pass, so this is not a compile/test-red problem; it is API-surface correctness before we bless the new provider. |
|
Thanks! Will review. |
Add `provider: daytona` as a direct, label-tracked Linux backend that
calls the Daytona REST API for sandbox lifecycle and mints short-lived
SSH access tokens for each connection. Reuses Crabbox's existing rsync
sync path; no broker/coordinator integration, no VNC/desktop, no
Windows/macOS targets, no Tailscale.
Auth lives in env only (DAYTONA_API_KEY or DAYTONA_JWT_TOKEN, optional
DAYTONA_ORGANIZATION_ID, DAYTONA_API_URL); never in repo config.
Class -> resource mapping: standard->small, fast->medium,
large/beast->large; explicit cpu/memory/disk overrides supported via
`daytona.{cpu,memory,disk}` or matching CRABBOX_DAYTONA_* env vars.
Token-mode SSH makes `SSHTarget.Key` optional: `sshBaseArgsWithOptions`
omits `-i` when no key is set so token-bearing users connect through
`ssh.app.daytona.io`. Status, list, and timing JSON redact the SSH user
to `<token>` so credentials never land in logs.
00be307 to
b8f08f2
Compare
|
Rebased and pushed Addressed the latest Daytona review items:
Verification on pushed commit go test -count=1 ./...
go test -race -count=1 ./internal/cli/...
go vet ./...
go build -trimpath ./cmd/crabbox
git diff --check origin/main...HEADAll passed. |
Why now
Crabbox already supports Hetzner, AWS EC2, blacksmith-testbox, and static SSH. Daytona Sandboxes give Crabbox a fifth direct backend for fast, label-tracked Linux sandboxes via a documented REST API and short-lived SSH access tokens.
I'm submitting this as a draft RFC. Two prior third-party-provider PRs (#16, #24) were closed because they were "broad" and you'd preferred a "fresh, smaller design" if revisited. This PR is intentionally narrow, and I'd rather get a thumbs up or a clean close on scope before un-drafting.
Scope (deliberately small)
In:
provider: daytonadirect local provider (no broker, no coordinator).standard->small,fast->medium,large/beast->large) with optional cpu/memory/disk overrides.GET /sandbox,POST /sandbox,GET/DELETE /sandbox/{id},POST /sandbox/{id}/{start,stop},PUT /sandbox/{id}/labels,POST /sandbox/{id}/last-activity,POST /sandbox/{id}/ssh-access?expiresInMinutes=N.DAYTONA_API_KEY/DAYTONA_JWT_TOKEN, optionalDAYTONA_ORGANIZATION_ID, optionalDAYTONA_API_URL); perAGENTS.md, never in repo config.ssh <token>@ssh.app.daytona.io);SSHTarget.Keybecomes optional and-iis omitted when empty.<token>so credentials don't leak.Out (explicit, can revisit later):
Architecture
Modeled on
internal/cli/hcloud.go(HTTP client + Server abstraction + labels), not oninternal/cli/blacksmith.go(subprocess wrapping), because Daytona exposes a REST API and labels natively. ReusesdirectLeaseLabels,touchDirectLeaseLabels,summarizeJSON,claimLeaseForRepoProvider,resolveLeaseClaim,leaseProviderName,allocateDirectLeaseSlug,serverSlug,findServerByAlias-style resolution.Dispatch sites added alongside existing branches in:
run.go(warmup, run, acquire, findLease, stop, deleteServer, touchDirectLeaseBestEffort)pool.go(list)status.go(status JSON, with token redaction)doctor.go(env+API ping)ssh.go'ssshBaseArgsWithOptionsnow omits both-iandIdentitiesOnly=yeswhenSSHTarget.Key == \"\". TheKeyfield gets a doc comment noting empty is valid for bearer-token auth.Verification
Pre-merge prerequisites for users
Daytona only — no Crabbox-side changes:
Both are documented in `docs/features/daytona.md`.
Test plan