Skip to content

feat(vercel): add Vercel Sandbox provider#16

Draft
madarco wants to merge 5 commits into
mainfrom
agentbox/fork-104454
Draft

feat(vercel): add Vercel Sandbox provider#16
madarco wants to merge 5 commits into
mainfrom
agentbox/fork-104454

Conversation

@madarco
Copy link
Copy Markdown
Owner

@madarco madarco commented May 28, 2026

Summary

  • Adds @agentbox/sandbox-vercel (--provider vercel), a fourth backend on top of @vercel/sandbox (Firecracker microVMs + snapshots), composed via the shared CloudBackend scaffolding like Daytona/Hetzner.
  • Base env is baked once via agentbox prepare --provider vercel (Vercel can't build from a Dockerfile): boot node24 → run provision.sh (AL2023: dnf deps, vscode user, agentbox-ctl + shims, Claude native installer, codex/opencode) → sandbox.snapshot().
  • Persistent sandboxes give pause/resume for free (stop auto-snapshots, get({resume:true}) resumes); destroy purges the box's snapshot. Public HTTPS preview URLs via sandbox.domain(port).
  • No in-box dockerd (Vercel blocks nested containers) and no SSH — interactive attach is a custom attach-helper.js tmux bridge (send-keys/capture-pane) over the SDK.
  • Checkpoints store the Vercel snapshot id in the cloud-checkpoint manifest (Vercel snapshots are id-addressed).
  • OIDC auth decodes the JWT's owner_id/project_id and passes explicit creds — the SDK's env-OIDC path needs Vercel-CLI linkage a box doesn't have (found via live testing; also detects expired tokens with a clear message).

Wiring

  • Provider registry + argv-prefix sugar + agentbox vercel CLI command.
  • Config: ProviderKind + box.defaultCheckpointVercel (+ JSON schema + checkpoint key resolution).
  • Relay resolveCloudBackend learns vercel.
  • launchDockerd opt-out added to the cloud scaffold.
  • apps/cli bundles the SDK as external (undici uses dynamic require, which breaks the ESM bundle otherwise).

Test plan

  • pnpm build && pnpm lint && pnpm typecheck && pnpm test all green (new unit tests: env-loader, credentials incl. OIDC decode/expiry, prepared-state, backend with mocked SDK, build-attach).
  • CLI smoke: vercel --help, vercel login --status, create --provider vercel routes correctly and surfaces the prepare gate; auth path reaches the Vercel API (verified live — blocked only by an expired OIDC token).
  • Full live e2e (prepare → create → attach → checkpoint) pending a non-expired Vercel credential. Live-verify checklist in docs/vercel-backlog.md.

Note

Medium Risk
Introduces a new billable cloud backend (snapshots, credentials, lifecycle) with several platform footguns, though it follows existing cloud patterns and includes mocked tests plus documented live fixes.

Overview
Adds Vercel Sandbox as a fourth backend (--provider vercel) via new @agentbox/sandbox-vercel, wired through the same CloudBackend / createCloudProvider path as Daytona and Hetzner.

Prepare & boot: One-time agentbox prepare --provider vercel bakes a base snapshot on Amazon Linux 2023 (provision.sh, no Dockerfile). Each box boots from that snapshot or a checkpoint snapshot id; persistent stop/resume maps to Vercel auto-snapshot + Sandbox.get({ resume: true }).

Platform differences: In-box dockerd is disabled (launchDockerd: false). No SSH — attach uses a host attach-helper.js tmux bridge over the SDK. Checkpoints store the Vercel snapshot id in the cloud manifest (custom checkpoint override). Preview URLs use public sandbox.domain(port) (relay on 8788; privileged port 80 not exposed on Vercel).

CLI & config: Registry, argv sugar (agentbox vercel create|…), agentbox vercel login (OIDC or token trio), box.defaultCheckpointVercel, relay backend resolution, @vercel/sandbox as an external CLI dependency. Docs: docs/vercel-backlog.md, docs/vercel-sandbox-findings.md, updates to CLAUDE.md and docs/cloud-providers.md. Live e2e harness scripts/vercel-live-e2e.sh plus fixes for AL2023 sudoers, destroy vs shared base snapshot, and prepare skip-fast on deleted snapshots.

Reviewed by Cursor Bugbot for commit 732048b. Configure here.

madarco added 4 commits May 28, 2026 11:15
Adds `@agentbox/sandbox-vercel` (`--provider vercel`), a fourth backend
built on @vercel/sandbox (Firecracker microVMs + snapshots), composed via
the shared CloudBackend scaffolding like Daytona/Hetzner.

- Base env baked once via `agentbox prepare --provider vercel` (Vercel can't
  build from a Dockerfile): boot node24 → provision.sh → sandbox.snapshot().
- Persistent sandboxes give pause/resume for free (stop auto-snapshots,
  get({resume:true}) resumes); destroy purges the box's snapshot.
- Public HTTPS preview URLs via sandbox.domain(port); no in-box dockerd
  (no nested containers) and no SSH (custom tmux attach helper over the SDK).
- Checkpoints store the Vercel snapshot id in the cloud-checkpoint manifest.
- OIDC auth decodes the JWT's owner_id/project_id and passes explicit creds
  (the SDK's env-OIDC path needs Vercel-CLI linkage a box doesn't have).

Wires registry/argv-prefix/CLI, config (ProviderKind + defaultCheckpointVercel
+ schema), relay resolveCloudBackend, and a launchDockerd opt-out in the cloud
scaffold. Includes unit tests + docs (cloud-providers.md, vercel-backlog.md).
Enumerate the P0 live-smoke items (nothing run end-to-end against real
Vercel yet — both dev OIDC tokens were expired), P1 functional gaps
(VNC on AL2023, attach latency/ttyd, published-CLI asset staging, builder
cleanup, OIDC expiry, per-provider resource config), and P2 deferred parity
work (checkpoint list view, per-project snapshot tier, prune, fork, ports,
networkPolicy).
…shot status on prepare skip

Two bugs found during the first live e2e:

- `destroy` purged `currentSnapshotId`, which for a box that hasn't paused is
  still the snapshot it booted from — so destroying any box deleted the shared
  base snapshot (and broke every subsequent create with a 410). Guard the purge
  with `currentSnapshotId !== sourceSnapshotId` so a box's own auto-snapshot is
  still cleaned but the base / checkpoint source survives.
- `prepare`'s skip-fast treated "Snapshot.get didn't throw" as "exists", but the
  SDK resolves deleted/failed tombstones too (status field). Require
  status === 'created' so a deleted base triggers a real rebuild.

Verified live: prepare bakes the base, create boots from it (user=vscode,
/workspace on agentbox/<box>, claude/codex/opencode present, docker correctly
unavailable), public *.vercel.run URL resolves, and destroy preserves the base.
@madarco madarco marked this pull request as draft May 28, 2026 16:13
…udo works

Vercel's AL2023 base ships /etc/sudoers without an includedir for
/etc/sudoers.d (and with non-0440 perms), so provision.sh's NOPASSWD drop-in
for vscode was silently ignored: `sudo -n` as vscode failed with "a password
is required", which broke the cloud workspace seed ($SUDO rm/mkdir/chown) and
would break ctl-launch / carry too. provision.sh now appends the includedir,
normalises perms to 0440, and visudo-validates.

Surfaced while running the remaining P0 live e2e (pause/resume + checkpoint
round-trip), now validated 11/11 from the host against a re-baked base. Also:

- scripts/vercel-live-e2e.sh: harness for #5/#6 + the destroy/base regression.
  Reads live SDK status (agentbox list reports cloud boxes as optimistically
  running), moves the /workspace marker over `agentbox cp`, reads the snapshot
  id from the checkpoint manifest, uses --carry skip for non-TTY runs.
- packages/sandbox-vercel/test/live-state.mjs: live Vercel status helper.
- docs/vercel-backlog.md: #5/#6 marked validated; three live bugs documented.
- docs/vercel-sandbox-findings.md: platform issues written up for Vercel.
@madarco
Copy link
Copy Markdown
Owner Author

madarco commented May 28, 2026

bugbot run

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 732048b. Configure here.

# gh + git shims win on PATH (/usr/local/bin precedes /usr/bin) so agent calls
# to `gh ...` / `git push|pull|fetch|clone` route through the relay.
install -m 0755 /tmp/agentbox-gh-shim /usr/local/bin/gh
install -m 0755 /tmp/agentbox-git-shim /usr/local/bin/git
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Git shim installed before git clone breaks noVNC setup

Medium Severity

The "baked helper scripts" step installs the relay-routing git shim to /usr/local/bin/git (which takes PATH precedence over /usr/bin/git) before the "VNC stack" step runs git clone to fetch noVNC. During provisioning there is no relay, so the shim cannot route the clone operation, causing the noVNC clone to silently fail. The git shim installation needs to happen after all direct git usage in the script.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 732048b. Configure here.

const prelude: string[] = [];
if (opts?.cwd) prelude.push(`cd ${shq(opts.cwd)}`);
for (const [k, v] of Object.entries(opts?.env ?? {})) {
prelude.push(`export ${k}=${shq(v)}`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unquoted env var keys allow shell injection

Low Severity

In buildRunCommand, environment variable values are properly shell-quoted via shq(v), but the keys (k) are interpolated raw into the shell command string. A key containing shell metacharacters (e.g. ; rm -rf /) would be interpreted by bash. The command runs with sudo: true. The key needs the same shq() treatment or at minimum an alphanumeric-only validation.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 732048b. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant