feat(workspace): mb workspace lifecycle — CRUD, credential sweep, destroy safety, --spawn#39
feat(workspace): mb workspace lifecycle — CRUD, credential sweep, destroy safety, --spawn#39escherize wants to merge 16 commits into
Conversation
Thin wrappers over /api/ee/workspace-manager (EE, v62+, workspaces premium feature). create provisions warehouse isolation blocking; destroy confirms, supports --ignore-pending, and surfaces orphaned_resources. Lifecycle e2e self-skips until the server carries the workspaces token feature. connect + profile-write land with the parent credentials endpoint. Refs GHY-4050
${VAR:-} injected an empty METASTORE_DEV_SERVER_URL; Metabase's
dev-mode token check treats empty as configured and builds a hostless
URL, so token validation always failed. Bare list-syntax entries only
pass through when the shell defines them, letting the staging
token-check fallback work.
…oped grant The scoped token is the containment primitive for Option B: a parent credential on an agent's machine that can only do workspace CRUD, enforced server-side by default-deny scope middleware. - scope threads through discovery gating, dynamic client registration, the authorize URL, the stored credential, and refresh (which sends no scope parameter, so a refresh can never widen the grant) - pre-scope profile records resolve to mb:full, which is what every legacy login was minted with - workspace login is browser-OAuth only: --api-key, MB_API_KEY, and non-TTY contexts are refused so a key can't masquerade as scoped - a 403 on a scope-narrowed profile is enriched to name the scope and the fix instead of a bare "Forbidden." Refs GHY-4053
Tier 2 of the containment ladder: a stale full-power credential for the same parent (any api-key profile, any OAuth grant wider than mb:workspace-manager) would let a confused agent bypass the scoped token, so create refuses while one exists. Interactive runs offer revocation (local clear + best-effort server-side token revocation); non-interactive runs hard-refuse — --keep-existing-auth is the human-only override and is itself refused without a TTY. The profile the command runs as is exempt: it is in deliberate use, not lying around. connect gets the same sweep when it lands (GHY-4052). Refs GHY-4054
Newer oxlint flags helpers that capture nothing from their describe. Refs GHY-4053
Destroy is the only irreversible moment, so it closes the work-loss window there: when a ws-<name> profile exists locally, the child is checked for unsynced work and a dirty workspace is auto-exported to its target branch before teardown. --discard skips both. No local profile warns and proceeds (destroy is the billing-stop lever; ops cleanup must work from any machine); an unreachable child refuses without --discard rather than silently reopening the window. The matching profile is dropped after a successful destroy. Refs GHY-4051
… profile The spawn response's url/api_key were previously dropped; a shell script did the profile write. Now --spawn sends spawn_instance, writes the credential straight to the ws-<id> profile (never stdout, never --json), and points a new defaultProfile pointer in profiles.json at it, so bare mb targets the fresh workspace. Explicit --profile/MB_PROFILE still win; clearing the profile (logout or destroy's drop) unhooks the pointer so it never dangles. Because an exported MB_API_KEY outranks stored profiles, --spawn refuses while it is set rather than installing a default it would silently shadow. Refs GHY-4075
|
Warning Review limit reached
Next review available in: 26 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (40)
✨ 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 |
"point --profile at a workspace profile" read as another workspace-scoped parent profile, which would also 403; the intended target is the child's ws-<id> profile. Refs GHY-4053
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
Published Install: |
Refs GHY-4050, GHY-4054, GHY-4051, GHY-4075 (Linear). Pairs with #34 (
auth login --workspace) — merge #34 first: the sweep reads theoauth.scopefield it introduces, so its two commits appear in this diff until it lands.The CLI half of Option B's workspace lifecycle: a local agent drives a disposable cloud Metabase, and every safety rail the architecture doc calls for on the client side lands here. Four layers, one arc:
1.
mb workspaceCRUD (GHY-4050)Thin wrappers over EE
/api/ee/workspace-manager, gated{ minVersion: 62, tokenFeature: "workspaces" }(endpoint is master-only; verified absent from release-x.61.x).createprovisions warehouse isolation blocking — the response carries final per-database status.destroyconfirms, supports--ignore-pending, surfacesorphaned_resources. Domain trio insrc/domain/workspace.tswith provisioning status pinned as a closed enum.2. Stale-credential sweep at create (GHY-4054)
Tier 2 of the containment ladder:
workspace createrefuses while the profile store holds a broader same-server credential (any api-key profile; any OAuth grant wider thanmb:workspace-manager). Interactive runs offer revocation (durable local clear, then best-effort server-side revocation); non-interactive runs hard-refuse —--keep-existing-authis the human-only override and is itself refused without a TTY, so an agent can never talk itself past the sweep.3. Destroy safety (GHY-4051)
Destroy is the only irreversible moment, so the work-loss window closes there: with a
ws-<id>profile present, the child is checked viaremote-sync is-dirtyand a dirty workspace auto-exports to its target branch before teardown (--discardskips). No local profile → warn and proceed (destroy is the billing-stop lever; ops cleanup works from any machine). Unreachable child → refuse without--discard. The profile is dropped after success.4.
create --spawndefault profile (GHY-4075)--spawnsendsspawn_instance: true; the returnedurl/api_keygo straight to thews-<id>profile — never stdout, never--json— and adefaultProfilepointer makes barembtarget the new workspace. Explicit--profile/MB_PROFILEwin;clearProfileunhooks the pointer so it never dangles; an exportedMB_API_KEY(which would shadow the pointer) makes--spawnrefuse up front.Test plan
--discard), spawn env-shadow guard. 894 unit tests. All 10 CI e2e lanes green pre-consolidation.--spawnend-to-end needs the parent'sspawn_instancesupport.