From 3bdfe919cfe3ed78cf309cd7716de15045266d4e Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 10 Nov 2026 19:23:56 -0800 Subject: [PATCH] fix(cloud): resolve the sandbox id of composer-created Orca Cloud workspaces (recipe without provider) Real-app m4air: per-workspace Sources (#287's workspaceSources, used by RA-11's D13 gate, the build-sheet Source menu and cloud secrets) answered not_found for every workspace the current composer creates, because its runtime record's recipe carries no provider. orcaCloudSandboxIdFor now accepts a missing provider, like cloud-desktop-keys does; the hosted-sandbox handle remains the proof. Tests cover provider-less, explicit, other-provider, handle-less and unknown runtimes. --- .../orca-cloud-sandbox-id.test.ts | 45 +++++++++++++++++++ .../hosted-sandbox/orca-cloud-sandbox-id.ts | 4 +- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 src/main/hosted-sandbox/orca-cloud-sandbox-id.test.ts diff --git a/src/main/hosted-sandbox/orca-cloud-sandbox-id.test.ts b/src/main/hosted-sandbox/orca-cloud-sandbox-id.test.ts new file mode 100644 index 00000000000..78b329fc44a --- /dev/null +++ b/src/main/hosted-sandbox/orca-cloud-sandbox-id.test.ts @@ -0,0 +1,45 @@ +import { describe, expect, it, vi } from 'vitest' + +const runtimes = vi.hoisted(() => ({ list: [] as unknown[] })) +vi.mock('../../shared/ephemeral-vm-runtime-store', () => ({ + listEphemeralVmRuntimes: () => runtimes.list +})) +vi.mock('../environment-providers/environment-provider-recipe-adapter', () => ({ + environmentHandleFromRecipeResult: (result: { sandboxId?: string } | undefined) => + result?.sandboxId ? { environmentId: result.sandboxId } : null +})) + +const { orcaCloudSandboxIdFor } = await import('./orca-cloud-sandbox-id') + +describe('orcaCloudSandboxIdFor', () => { + it('resolves composer-created cloud workspaces whose recipe has no provider (RA-11)', () => { + runtimes.list = [ + { + runtimeEnvironmentId: 'env-a', + recipe: { id: 'cloud' }, + recipeResult: { sandboxId: 'sbx_a' } + }, + { + runtimeEnvironmentId: 'env-b', + recipe: { id: 'cloud', provider: 'orca-cloud' }, + recipeResult: { sandboxId: 'sbx_b' } + } + ] + expect(orcaCloudSandboxIdFor('/u', 'env-a')).toBe('sbx_a') + expect(orcaCloudSandboxIdFor('/u', 'env-b')).toBe('sbx_b') + }) + + it('never resolves another provider, an unknown runtime, or one without a hosted-sandbox handle', () => { + runtimes.list = [ + { + runtimeEnvironmentId: 'env-c', + recipe: { provider: 'custom' }, + recipeResult: { sandboxId: 'x' } + }, + { runtimeEnvironmentId: 'env-d', recipe: { id: 'cloud' }, recipeResult: {} } + ] + expect(orcaCloudSandboxIdFor('/u', 'env-c')).toBeNull() + expect(orcaCloudSandboxIdFor('/u', 'env-d')).toBeNull() + expect(orcaCloudSandboxIdFor('/u', 'env-zzz')).toBeNull() + }) +}) diff --git a/src/main/hosted-sandbox/orca-cloud-sandbox-id.ts b/src/main/hosted-sandbox/orca-cloud-sandbox-id.ts index d312c200e1a..17e6e98bfe0 100644 --- a/src/main/hosted-sandbox/orca-cloud-sandbox-id.ts +++ b/src/main/hosted-sandbox/orca-cloud-sandbox-id.ts @@ -12,7 +12,9 @@ export function orcaCloudSandboxIdFor( const runtime = listEphemeralVmRuntimes(userDataPath).find( (record) => record.runtimeEnvironmentId === runtimeEnvironmentId && - record.recipe?.provider === 'orca-cloud' + // Composer-created cloud workspaces store the recipe without a provider (like + // cloud-desktop-keys); the hosted-sandbox handle below is what proves it is Orca Cloud. + (record.recipe?.provider === 'orca-cloud' || record.recipe?.provider === undefined) ) const handle = runtime?.recipeResult ? environmentHandleFromRecipeResult(runtime.recipeResult, HOSTED_SANDBOX_DRIVER_ID)