import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { encodePairingOffer, PAIRING_OFFER_VERSION } from '../../shared/pairing' import { listEnvironments } from '../../shared/runtime-environment-store' import { upsertEphemeralVmRuntime } from '../../shared/ephemeral-vm-runtime-store' const handlers = new Map unknown>() const { handleMock, removeHandlerMock, getPathMock, connectRuntimeOwnedSshTargetMock, disconnectRuntimeOwnedSshTargetMock, removeRuntimeOwnedSshTargetMock, invalidateRuntimeEnvironmentTransportMock } = vi.hoisted(() => ({ handleMock: vi.fn(), removeHandlerMock: vi.fn(), getPathMock: vi.fn(), connectRuntimeOwnedSshTargetMock: vi.fn(), disconnectRuntimeOwnedSshTargetMock: vi.fn(), removeRuntimeOwnedSshTargetMock: vi.fn(), invalidateRuntimeEnvironmentTransportMock: vi.fn() })) vi.mock('electron', () => ({ app: { getPath: getPathMock }, ipcMain: { handle: handleMock, removeHandler: removeHandlerMock } })) vi.mock('../ephemeral-vm-runtime-ssh', () => ({ connectRuntimeOwnedSshTarget: connectRuntimeOwnedSshTargetMock, disconnectRuntimeOwnedSshTarget: disconnectRuntimeOwnedSshTargetMock, removeRuntimeOwnedSshTarget: removeRuntimeOwnedSshTargetMock })) vi.mock('./runtime-environments', () => ({ invalidateRuntimeEnvironmentTransport: invalidateRuntimeEnvironmentTransportMock })) import { registerEphemeralVmHandlers } from './ephemeral-vm' const tempDirs: string[] = [] afterEach(() => { for (const dir of tempDirs.splice(0)) { rmSync(dir, { recursive: true, force: true }) } }) function makeDir(prefix: string): string { const dir = mkdtempSync(join(tmpdir(), prefix)) tempDirs.push(dir) return dir } function makePairingCode(): string { return encodePairingOffer({ v: PAIRING_OFFER_VERSION, endpoint: 'wss://sandbox.example.com', deviceToken: 'token', publicKeyB64: 'public-key' }) } function makeStore(repoPath: string) { const repo = { id: 'repo-1', path: repoPath, displayName: 'Repo', badgeColor: '#000', addedAt: 0 } let activeRuntimeEnvironmentId: string | null = null return { getRepo: vi.fn((repoId: string) => (repoId === 'repo-1' ? repo : null)), getRepos: vi.fn(() => [repo]), getSettings: vi.fn(() => ({ activeRuntimeEnvironmentId })), updateSettings: vi.fn((updates: { activeRuntimeEnvironmentId: string | null }) => { activeRuntimeEnvironmentId = updates.activeRuntimeEnvironmentId }) } } function nodeCommand(scriptPath: string): string { return `"${process.execPath}" "${scriptPath}"` } function pluginServiceWithRecipes( recipes: { pluginKey: string; recipe: Record }[] ) { return { whenReady: vi.fn().mockResolvedValue(undefined), contentPacks: { vmRecipes: { list: vi.fn(() => recipes) } } } } describe('registerEphemeralVmHandlers', () => { const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform') beforeEach(() => { Object.defineProperty(process, 'platform', { configurable: true, value: 'linux' }) handlers.clear() handleMock.mockReset() removeHandlerMock.mockReset() getPathMock.mockReset() connectRuntimeOwnedSshTargetMock.mockReset() disconnectRuntimeOwnedSshTargetMock.mockReset() removeRuntimeOwnedSshTargetMock.mockReset() invalidateRuntimeEnvironmentTransportMock.mockReset() connectRuntimeOwnedSshTargetMock.mockResolvedValue({ targetId: 'runtime-ssh-orca-instance-1', target: { id: 'runtime-ssh-orca-instance-1', label: 'Sandbox', host: 'sandbox.example.com', port: 22, username: 'root' } }) disconnectRuntimeOwnedSshTargetMock.mockResolvedValue(undefined) removeRuntimeOwnedSshTargetMock.mockResolvedValue(undefined) handleMock.mockImplementation((channel: string, handler: never) => { handlers.set(channel, handler) }) }) afterEach(() => { if (originalPlatform) { Object.defineProperty(process, 'platform', originalPlatform) } }) it('lists recipes from local repo orca.yaml', async () => { const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') writeFileSync( join(repoPath, 'orca.yaml'), [ 'environmentRecipes:', ' - id: cloud-sandbox', ' name: Cloud Sandbox', ' create: ./scripts/start.sh', ' destroy: none' ].join('\n') ) const store = makeStore(repoPath) registerEphemeralVmHandlers(store as never) const result = await handlers.get('ephemeralVm:listRecipes')?.(null, { repoId: 'repo-1' } as never) expect(removeHandlerMock).toHaveBeenCalledWith('ephemeralVm:listRecipes') expect(result).toEqual({ status: 'ok', repoPath, diagnostics: [], recipes: [ { id: 'cloud-sandbox', name: 'Cloud Sandbox', create: './scripts/start.sh', destroyDisabled: true } ] }) }) it('lists the recipe catalog across local git repos', async () => { const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') writeFileSync( join(repoPath, 'orca.yaml'), [ 'environmentRecipes:', ' - id: cloud-sandbox', ' name: Cloud Sandbox', ' create: ./scripts/start.sh', ' destroy: none' ].join('\n') ) const store = makeStore(repoPath) registerEphemeralVmHandlers(store as never) const result = await handlers.get('ephemeralVm:listRecipeCatalog')?.(null, undefined as never) expect(result).toEqual([ { repoId: 'repo-1', repoName: 'Repo', repoPath, diagnostics: [], recipes: [ { id: 'cloud-sandbox', name: 'Cloud Sandbox', create: './scripts/start.sh', destroyDisabled: true } ] } ]) }) it('merges approved plugin recipes while repository recipes shadow matching ids', async () => { const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') writeFileSync( join(repoPath, 'orca.yaml'), [ 'environmentRecipes:', ' - id: shared', ' name: Repository Recipe', ' create: repo-create' ].join('\n') ) const pluginService = pluginServiceWithRecipes([ { pluginKey: 'orca-samples.recipes', recipe: { id: 'shared', name: 'Plugin Shared', create: 'plugin-shared' } }, { pluginKey: 'orca-samples.recipes', recipe: { id: 'global', name: 'Plugin Global', create: 'plugin-global' } } ]) registerEphemeralVmHandlers(makeStore(repoPath) as never, pluginService as never) const result = (await handlers.get('ephemeralVm:listRecipes')?.(null, { repoId: 'repo-1' } as never)) as { recipes: { id: string; name: string }[] } expect(pluginService.whenReady).toHaveBeenCalled() expect(result.recipes).toMatchObject([ { id: 'shared', name: 'Repository Recipe' }, { id: 'global', name: 'Plugin Global' } ]) }) it('uses an immutable plugin recipe snapshot after the plugin is removed', async () => { const userDataPath = makeDir('orca-ephemeral-vm-ipc-user-data-') const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') getPathMock.mockReturnValue(userDataPath) const startPath = join(repoPath, 'start.js') const destroyPath = join(repoPath, 'destroy.js') writeFileSync( startPath, `console.log(${JSON.stringify( JSON.stringify({ schemaVersion: 1, pairingCode: makePairingCode(), projectRoot: '/workspace/repo' }) )})` ) writeFileSync(destroyPath, "require('fs').writeFileSync('plugin-cleaned.txt', 'yes')") const registrations = [ { pluginKey: 'orca-samples.recipes', recipe: { id: 'plugin-cloud', name: 'Plugin Cloud', create: nodeCommand(startPath), destroy: nodeCommand(destroyPath) } } ] const pluginService = pluginServiceWithRecipes(registrations) registerEphemeralVmHandlers(makeStore(repoPath) as never, pluginService as never) const provisioned = (await handlers.get('ephemeralVm:provision')?.(null, { repoId: 'repo-1', recipeId: 'plugin-cloud' } as never)) as { ok: true; runtime: { id: string; recipe?: { id: string } } } registrations.splice(0) const cleaned = await handlers.get('ephemeralVm:cleanup')?.(null, { runtimeId: provisioned.runtime.id } as never) expect(provisioned.runtime.recipe).toMatchObject({ id: 'plugin-cloud' }) expect(cleaned).toEqual(expect.objectContaining({ status: 'cleaned' })) expect(readFileSync(join(repoPath, 'plugin-cleaned.txt'), 'utf8')).toBe('yes') }) it('never substitutes a later same-id plugin recipe for a legacy runtime', async () => { const userDataPath = makeDir('orca-ephemeral-vm-ipc-user-data-') const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') getPathMock.mockReturnValue(userDataPath) const pluginDestroyPath = join(repoPath, 'plugin-destroy.js') writeFileSync( pluginDestroyPath, "require('fs').writeFileSync('plugin-destroy-ran.txt', 'unsafe')" ) upsertEphemeralVmRuntime(userDataPath, { id: 'legacy-runtime', recipeId: 'shared-id', repoId: 'repo-1', status: 'running', cleanupStatus: 'not_started', createdAt: 1, updatedAt: 1, recipeResult: { schemaVersion: 1, pairingCode: makePairingCode(), projectRoot: '/workspace/repo' } }) const pluginService = pluginServiceWithRecipes([ { pluginKey: 'orca-samples.recipes', recipe: { id: 'shared-id', name: 'Later Plugin Recipe', create: 'create', destroy: nodeCommand(pluginDestroyPath) } } ]) registerEphemeralVmHandlers(makeStore(repoPath) as never, pluginService as never) const cleaned = await handlers.get('ephemeralVm:cleanup')?.(null, { runtimeId: 'legacy-runtime' } as never) expect(cleaned).toMatchObject({ status: 'cleanup_failed', cleanupLastError: 'Recipe not found: shared-id' }) expect(existsSync(join(repoPath, 'plugin-destroy-ran.txt'))).toBe(false) }) it('provisions a recipe and persists the ephemeral runtime', async () => { const userDataPath = makeDir('orca-ephemeral-vm-ipc-user-data-') const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') getPathMock.mockReturnValue(userDataPath) mkdirSync(join(repoPath, 'scripts'), { recursive: true }) const startPath = join(repoPath, 'scripts', 'start.js') writeFileSync( startPath, [ 'console.log(JSON.stringify({', ' schemaVersion: 1,', ` pairingCode: ${JSON.stringify(makePairingCode())},`, " projectRoot: '/workspace/repo',", ' userData: { providerResourceId: process.env.ORCA_VM_INSTANCE_ID }', '}))' ].join('\n') ) writeFileSync( join(repoPath, 'orca.yaml'), [ 'environmentRecipes:', ' - id: cloud-sandbox', ' name: Cloud Sandbox', ` create: ${JSON.stringify(nodeCommand(startPath))}`, ' destroy: none' ].join('\n') ) const store = makeStore(repoPath) registerEphemeralVmHandlers(store as never) const result = (await handlers.get('ephemeralVm:provision')?.(null, { repoId: 'repo-1', recipeId: 'cloud-sandbox', workspaceName: 'Fix Login Race' } as never)) as { ok: boolean runtime?: { id: string; repoId?: string; status?: string; runtimeEnvironmentId?: string } environment?: { id: string; name: string } } expect(result).toMatchObject({ ok: true, environment: { name: expect.stringContaining('Repo VM ') }, runtime: { repoId: 'repo-1', status: 'running', runtimeEnvironmentId: result.environment?.id } }) const runtimes = await handlers.get('ephemeralVm:listRuntimes')?.(null, undefined as never) expect(runtimes).toEqual([ expect.objectContaining({ repoId: 'repo-1', recipeId: 'cloud-sandbox', runtimeEnvironmentId: result.environment?.id }) ]) const attached = await handlers.get('ephemeralVm:attachWorkspace')?.(null, { runtimeId: result.runtime?.id, workspaceId: 'repo-1::/workspace/repo/worktree' } as never) expect(attached).toEqual( expect.objectContaining({ id: result.runtime?.id, workspaceId: 'repo-1::/workspace/repo/worktree' }) ) store.updateSettings({ activeRuntimeEnvironmentId: result.environment!.id }) const cleaned = await handlers.get('ephemeralVm:cleanup')?.(null, { runtimeId: result.runtime?.id } as never) expect(cleaned).toEqual(expect.objectContaining({ status: 'cleaned' })) expect(listEnvironments(userDataPath)).toEqual([]) expect(store.getSettings().activeRuntimeEnvironmentId).toBe(result.environment!.id) expect(store.updateSettings).toHaveBeenCalledTimes(1) }) it('provisions an ssh recipe without creating a runtime environment', async () => { const userDataPath = makeDir('orca-ephemeral-vm-ipc-user-data-') const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') getPathMock.mockReturnValue(userDataPath) mkdirSync(join(repoPath, 'scripts'), { recursive: true }) const startPath = join(repoPath, 'scripts', 'start-ssh.js') writeFileSync( startPath, [ 'console.log(JSON.stringify({', ' schemaVersion: 1,', ' connection: {', " type: 'ssh',", " projectRoot: '/workspace/repo',", ' target: {', " label: 'Sandbox',", " host: 'sandbox.example.com',", ' port: 22,', " username: 'root'", ' }', ' },', " userData: { sandboxId: 'sandbox-123' }", '}))' ].join('\n') ) writeFileSync( join(repoPath, 'orca.yaml'), [ 'environmentRecipes:', ' - id: cloud-sandbox', ' name: Cloud Sandbox', ` create: ${JSON.stringify(nodeCommand(startPath))}`, ' destroy: none' ].join('\n') ) registerEphemeralVmHandlers(makeStore(repoPath) as never) const result = (await handlers.get('ephemeralVm:provision')?.(null, { repoId: 'repo-1', recipeId: 'cloud-sandbox', workspaceName: 'Fix Login Race' } as never)) as { ok: boolean connectionType?: string sshTargetId?: string runtime?: { id: string repoId?: string status?: string connectionMode?: string sshTargetId?: string } environment?: { id: string; name: string } } expect(result).toMatchObject({ ok: true, connectionType: 'ssh', sshTargetId: 'runtime-ssh-orca-instance-1', runtime: { repoId: 'repo-1', status: 'running', connectionMode: 'ssh', sshTargetId: 'runtime-ssh-orca-instance-1' } }) expect(result.environment).toBeUndefined() expect(connectRuntimeOwnedSshTargetMock).toHaveBeenCalledWith({ runtimeId: result.runtime?.id, connection: { type: 'ssh', projectRoot: '/workspace/repo', target: { label: 'Sandbox', host: 'sandbox.example.com', port: 22, username: 'root' } } }) expect(listEnvironments(userDataPath)).toEqual([]) }) it('retains the runtime-owned SSH target when destroy fails', async () => { const userDataPath = makeDir('orca-ephemeral-vm-ipc-user-data-') const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') getPathMock.mockReturnValue(userDataPath) mkdirSync(join(repoPath, 'scripts'), { recursive: true }) const startPath = join(repoPath, 'scripts', 'start-ssh.js') const destroyPath = join(repoPath, 'scripts', 'destroy.js') writeFileSync( startPath, [ 'console.log(JSON.stringify({', ' schemaVersion: 1,', ' connection: {', " type: 'ssh',", " projectRoot: '/workspace/repo',", ' target: {', " label: 'Sandbox',", " host: 'sandbox.example.com',", ' port: 22,', " username: 'root'", ' }', ' }', '}))' ].join('\n') ) writeFileSync(destroyPath, 'process.exit(1)') writeFileSync( join(repoPath, 'orca.yaml'), [ 'environmentRecipes:', ' - id: cloud-sandbox', ' name: Cloud Sandbox', ` create: ${JSON.stringify(nodeCommand(startPath))}`, ` destroy: ${JSON.stringify(nodeCommand(destroyPath))}` ].join('\n') ) registerEphemeralVmHandlers(makeStore(repoPath) as never) const provisioned = (await handlers.get('ephemeralVm:provision')?.(null, { repoId: 'repo-1', recipeId: 'cloud-sandbox' } as never)) as { ok: true; runtime: { id: string } } const cleaned = (await handlers.get('ephemeralVm:cleanup')?.(null, { runtimeId: provisioned.runtime.id } as never)) as { status?: string cleanupLastError?: string connectionMode?: string sshTargetId?: string } expect(cleaned).toEqual(expect.objectContaining({ status: 'cleanup_failed' })) expect(cleaned.cleanupLastError).toBeTruthy() expect(removeRuntimeOwnedSshTargetMock).not.toHaveBeenCalled() expect(cleaned.connectionMode).toBe('ssh') expect(cleaned.sshTargetId).toBe('runtime-ssh-orca-instance-1') }) it('retries hidden SSH teardown without rerunning completed provider cleanup', async () => { const userDataPath = makeDir('orca-ephemeral-vm-ipc-user-data-') const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') getPathMock.mockReturnValue(userDataPath) upsertEphemeralVmRuntime(userDataPath, { id: 'runtime-cleanup-retry', recipeId: 'cloud-sandbox', repoId: 'repo-1', status: 'cleanup_failed', cleanupStatus: 'succeeded', connectionMode: 'ssh', sshTargetId: 'runtime-ssh-cleanup-retry', createdAt: 1, updatedAt: 1, recipeResult: { schemaVersion: 1, connection: { type: 'ssh', projectRoot: '/workspace/repo', target: { label: 'VM', host: 'host', port: 22, username: 'orca' } } } }) registerEphemeralVmHandlers(makeStore(repoPath) as never) removeRuntimeOwnedSshTargetMock.mockRejectedValueOnce(new Error('store unavailable')) const failed = await handlers.get('ephemeralVm:cleanup')?.(null, { runtimeId: 'runtime-cleanup-retry' } as never) expect(failed).toMatchObject({ status: 'cleanup_failed', cleanupStatus: 'succeeded', sshTargetId: 'runtime-ssh-cleanup-retry' }) removeRuntimeOwnedSshTargetMock.mockResolvedValue(undefined) const cleaned = await handlers.get('ephemeralVm:cleanup')?.(null, { runtimeId: 'runtime-cleanup-retry' } as never) expect(cleaned).toMatchObject({ status: 'cleaned', cleanupStatus: 'succeeded', sshTargetId: undefined }) expect(removeRuntimeOwnedSshTargetMock).toHaveBeenCalledTimes(2) }) it('runs suspend and resume for an attached ephemeral VM workspace', async () => { const userDataPath = makeDir('orca-ephemeral-vm-ipc-user-data-') const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') getPathMock.mockReturnValue(userDataPath) mkdirSync(join(repoPath, 'scripts'), { recursive: true }) const startPath = join(repoPath, 'scripts', 'start.js') const suspendPath = join(repoPath, 'scripts', 'suspend.js') const resumePath = join(repoPath, 'scripts', 'resume.js') const resumedPairingCode = encodePairingOffer({ v: PAIRING_OFFER_VERSION, endpoint: 'wss://resumed.example.com', deviceToken: 'resumed-token', publicKeyB64: 'resumed-public-key' }) writeFileSync( startPath, [ 'console.log(JSON.stringify({', ' schemaVersion: 1,', ` pairingCode: ${JSON.stringify(makePairingCode())},`, " projectRoot: '/workspace/repo'", '}))' ].join('\n') ) writeFileSync( suspendPath, [ "const fs = require('fs')", "const payload = JSON.parse(fs.readFileSync(0, 'utf8'))", "fs.writeFileSync('suspend-mode.txt', payload.mode)" ].join('\n') ) writeFileSync( resumePath, [ "const fs = require('fs')", "const payload = JSON.parse(fs.readFileSync(0, 'utf8'))", 'if (payload.mode !== "resume") process.exit(2)', "fs.writeFileSync('resume-mode.txt', payload.mode)", 'console.log(JSON.stringify({', ' schemaVersion: 1,', ` pairingCode: ${JSON.stringify(resumedPairingCode)},`, " projectRoot: '/workspace/resumed'", '}))' ].join('\n') ) writeFileSync( join(repoPath, 'orca.yaml'), [ 'environmentRecipes:', ' - id: cloud-sandbox', ' name: Cloud Sandbox', ` create: ${JSON.stringify(nodeCommand(startPath))}`, ` suspend: ${JSON.stringify(nodeCommand(suspendPath))}`, ` resume: ${JSON.stringify(nodeCommand(resumePath))}`, ' destroy: none' ].join('\n') ) registerEphemeralVmHandlers(makeStore(repoPath) as never) const provisioned = (await handlers.get('ephemeralVm:provision')?.(null, { repoId: 'repo-1', recipeId: 'cloud-sandbox' } as never)) as { ok: true; runtime: { id: string }; environment: { id: string } } await handlers.get('ephemeralVm:attachWorkspace')?.(null, { runtimeId: provisioned.runtime.id, workspaceId: 'workspace-1' } as never) const runningResume = await handlers.get('ephemeralVm:resumeWorkspace')?.(null, { workspaceId: 'workspace-1' } as never) expect(runningResume).toEqual(expect.objectContaining({ status: 'running' })) expect(existsSync(join(repoPath, 'resume-mode.txt'))).toBe(false) const suspended = await handlers.get('ephemeralVm:suspendWorkspace')?.(null, { workspaceId: 'workspace-1' } as never) expect(suspended).toEqual(expect.objectContaining({ status: 'suspended' })) expect(readFileSync(join(repoPath, 'suspend-mode.txt'), 'utf8')).toBe('suspend') invalidateRuntimeEnvironmentTransportMock.mockImplementationOnce((environmentId: string) => { const environment = listEnvironments(userDataPath).find((entry) => entry.id === environmentId) expect(environment?.endpoints[0]?.endpoint).toBe('wss://resumed.example.com') }) const resumed = await handlers.get('ephemeralVm:resumeWorkspace')?.(null, { workspaceId: 'workspace-1' } as never) expect(resumed).toEqual( expect.objectContaining({ status: 'running', recipeResult: expect.objectContaining({ projectRoot: '/workspace/resumed' }) }) ) expect(readFileSync(join(repoPath, 'resume-mode.txt'), 'utf8')).toBe('resume') const environment = listEnvironments(userDataPath).find( (entry) => entry.id === provisioned.environment.id ) expect(environment?.endpoints[0]?.endpoint).toBe('wss://resumed.example.com') expect(invalidateRuntimeEnvironmentTransportMock).toHaveBeenCalledWith( provisioned.environment.id ) }) it('returns a copyable cleanup command for a persisted runtime', async () => { const userDataPath = makeDir('orca-ephemeral-vm-ipc-user-data-') const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') getPathMock.mockReturnValue(userDataPath) mkdirSync(join(repoPath, 'scripts'), { recursive: true }) const startPath = join(repoPath, 'scripts', 'start.js') const cleanupPath = join(repoPath, 'scripts', 'cleanup.js') writeFileSync( startPath, [ 'console.log(JSON.stringify({', ' schemaVersion: 1,', ` pairingCode: ${JSON.stringify(makePairingCode())},`, " projectRoot: '/workspace/repo'", '}))' ].join('\n') ) writeFileSync(cleanupPath, 'process.stdin.resume()\n') writeFileSync( join(repoPath, 'orca.yaml'), [ 'environmentRecipes:', ' - id: cloud-sandbox', ' name: Cloud Sandbox', ` create: ${JSON.stringify(nodeCommand(startPath))}`, ` destroy: ${JSON.stringify(nodeCommand(cleanupPath))}` ].join('\n') ) registerEphemeralVmHandlers(makeStore(repoPath) as never) const provisioned = (await handlers.get('ephemeralVm:provision')?.(null, { repoId: 'repo-1', recipeId: 'cloud-sandbox', workspaceName: 'Fix Login Race' } as never)) as { ok: true; runtime: { id: string } } const result = await handlers.get('ephemeralVm:getCleanupCommand')?.(null, { runtimeId: provisioned.runtime.id } as never) expect(result).toMatchObject({ runtimeId: provisioned.runtime.id, cleanupDisabled: false, payloadJson: expect.stringContaining('"workspaceName": "Fix Login Race"'), command: expect.stringContaining(nodeCommand(cleanupPath)) }) }) it('streams provision logs and cancels an active provision', async () => { const userDataPath = makeDir('orca-ephemeral-vm-ipc-user-data-') const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') getPathMock.mockReturnValue(userDataPath) mkdirSync(join(repoPath, 'scripts'), { recursive: true }) const startPath = join(repoPath, 'scripts', 'start.js') writeFileSync( startPath, [ "process.stderr.write('creating sandbox\\n')", 'setTimeout(() => {', ' console.log(JSON.stringify({', ' schemaVersion: 1,', ` pairingCode: ${JSON.stringify(makePairingCode())},`, " projectRoot: '/workspace/repo'", ' }))', '}, 30000)' ].join('\n') ) writeFileSync( join(repoPath, 'orca.yaml'), [ 'environmentRecipes:', ' - id: cloud-sandbox', ' name: Cloud Sandbox', ` create: ${JSON.stringify(nodeCommand(startPath))}`, ' destroy: none' ].join('\n') ) registerEphemeralVmHandlers(makeStore(repoPath) as never) const sender = { send: vi.fn() } const provision = handlers.get('ephemeralVm:provision')?.({ sender }, { repoId: 'repo-1', recipeId: 'cloud-sandbox', workspaceName: 'Fix Login Race', provisionId: 'provision-1' } as never) as Promise<{ ok: boolean; error?: string }> await vi.waitFor(() => expect(sender.send).toHaveBeenCalledWith('ephemeralVm:provisionEvent', { provisionId: 'provision-1', stream: 'stderr', chunk: 'creating sandbox\n' }) ) const cancelled = await handlers.get('ephemeralVm:cancelProvision')?.(null, { provisionId: 'provision-1' } as never) const result = await provision expect(cancelled).toEqual({ cancelled: true }) expect(result.ok).toBe(false) }) it('redacts recipe stdout when provisioning fails', async () => { const userDataPath = makeDir('orca-ephemeral-vm-ipc-user-data-') const repoPath = makeDir('orca-ephemeral-vm-ipc-repo-') getPathMock.mockReturnValue(userDataPath) mkdirSync(join(repoPath, 'scripts'), { recursive: true }) const startPath = join(repoPath, 'scripts', 'start.js') writeFileSync( startPath, [ 'console.log(JSON.stringify({', ` pairingCode: ${JSON.stringify(makePairingCode())},`, " token: 'provider-token'", '}))' ].join('\n') ) writeFileSync( join(repoPath, 'orca.yaml'), [ 'environmentRecipes:', ' - id: cloud-sandbox', ' name: Cloud Sandbox', ` create: ${JSON.stringify(nodeCommand(startPath))}`, ' destroy: none' ].join('\n') ) registerEphemeralVmHandlers(makeStore(repoPath) as never) const result = (await handlers.get('ephemeralVm:provision')?.(null, { repoId: 'repo-1', recipeId: 'cloud-sandbox' } as never)) as { ok: false; stdout: string } expect(result.ok).toBe(false) expect(result.stdout).toContain('"pairingCode":"[redacted]"') expect(result.stdout).toContain('"token":"[redacted]"') expect(result.stdout).not.toContain('provider-token') expect(result.stdout).not.toContain('public-key') }) })