feat(desktop,trpc,host-service): cloud workspaces backed by Blaxel sandboxes
Cloud workspaces: one workspace is one Blaxel sandbox running host-service, reachable from the desktop app.
This was a five-PR stack (#6489, #6497, #6500, #6503, #6505) that has been collapsed into this one — same commits, rebased onto current main. The others are closed as superseded, not abandoned.
What it does
Create a cloud workspace from the app, get a sandbox with the repo cloned and an agent already authenticated, and drive it from the sidebar with the affordances a local workspace has: PR badges, agent status, rename, ordering, delete.
The parts worth reviewing
A sandbox is one repo, one project, one workspace, fixed at provision. machineOnlyProcedure refuses project/workspace CRUD inside one, whoever asks — agent, CLI or shell — because "add a project" produces state the cloud side can't see or clean up. The boot-time sweeps that repair a long-lived machine's accumulated state don't run there either: a sandbox is provisioned fresh, so they can only invent (the main-workspace sweep was adding a phantom second workspace before this).
The cloud row owns the workspace name. host-service's copy is ignored. Two sources of truth for a name was the original bug behind the rename flicker.
Agent credentials never enter a sandbox. The provider's egress proxy substitutes them at the edge from a {{SECRET:...}} routing rule; the sandbox env holds only a placeholder. An agent can use the key and can't read it.
A sandbox's host-service trusts the edge — please read this one. EdgeGuardedHostAuthProvider accepts every request. The gate is the private preview: the edge turns away anything without a preview token, and only our API can mint one. Keeping the PSK as a second layer was considered and rejected — one secret baked into every sandbox is a cross-tenant credential, and every sandbox hands an agent a shell that can read its own env. A second factor each tenant can read isn't one; it just makes the posture look deeper than it is. Consequence: public: false on the preview is now a security-critical setting.
Cloud-workspace env vars are required, not defaulted. A misconfigured deployment fails at boot instead of quietly degrading. Anyone with an existing root .env needs the four new keys from .env.example before the API will start.
Notes for review
- Migration is
0078, regenerated on top of0077. As0074its timestamp was earlier than main's own0074, so drizzle would have skipped it silently and forever — the table would never have been created in production. - Additive migration (one enum, one table, FKs only on the new table). Nothing alters an existing column.
- Creation is gated to
@superset.shaccounts while the path is unproven. docs/cloud-sandbox-mismatches.mdis the running list of places a sandbox doesn't behave like a machine someone owns;docs/cloud-sandbox-considerations.mdis what's still owed before non-internal users.
Known gaps
- The GitHub token in a sandbox's
.git/configis a write-scoped credential readable by anything inside. Needs a decision: strip the remote plus a credential broker, or a long-lived credential. - Pin is hidden for cloud rows — the Pinned section builds from local host data and would render the sandbox's stale name.
- No drag-ordering for cloud rows yet, and no reaper for rows stuck in
provisioning. - Untested: sandbox sleep/wake with a host-service restart, disk durability, token refresh after backgrounding.
Summary by CodeRabbit
- New Features
- Added cloud workspace creation, provisioning, repository bootstrapping, and branch selection.
- Cloud workspaces now appear in the dashboard sidebar with preview access.
- Added cloud workspace rename and deletion support.
- Added sandbox-aware connectivity, event updates, credential handling, and GitHub repository access.
- Bug Fixes
- Workspace names now update immediately while renaming.
- Improved readiness, access retries, and cleanup behavior.
- Documentation
- Added guidance on cloud sandbox limitations, security, lifecycle, and setup.