Files
orca/src/shared/remote-runtime-subscription-frame-router.test.ts
T
841503152c fix(runtime-environments): don't crash when a server removed via the CLI still responds (#22517)
* fix(runtime-environments): don't crash when a server removed via the CLI still responds

orca environment rm edits the environment store behind the running app, so the
next ok response on a live socket called markEnvironmentUsed, which threw
'Unknown environment' out of an unguarded socket callback. Main-process callers
now use markEnvironmentUsedIfPresent, which skips a missing environment and
keeps every other store error; the status owner pauses shared control instead
of re-establishing it for a removed server.

* fix(runtime-environments): guard usage bookkeeping at the main-process boundary

Keep one strict store contract and move the leniency to the caller that cannot
report a failure to anyone.

- Revert markEnvironmentUsedIfPresent: drawing the line around one error string
  left corrupt, unreadable and oversized store files still fatal on the same
  unguarded socket callback.
- Add recordRuntimeEnvironmentUsage, a named main-process boundary that says
  lastUsedAt is advisory and swallows every store failure. Route only the three
  sites with no observer through it (subscription onResponse in transport- and
  support-routing, and the status owner's verified hook, where a throw skips
  settleWaiters and hangs refresh callers). Awaited request paths stay strict.
- Guard onResponse/onBinary in the subscription frame router the way the sibling
  request router already guards validateStatus, so no consumer throw can reach
  the ws 'message' emitter and become main_uncaught_exception.
- Drop the status-owner `capable && present` gate: pauseStandingRetry no-ops
  while subscriptions exist, and removal teardown belongs to #21048's watcher.

Co-authored-by: mmarabel <mmarabel@users.noreply.github.com>

* test(runtime-environments): cover the real socket path a consumer throw escapes

The existing tests invoke the captured onResponse directly, which never touches
the surface that actually kills the app. Drive a real WebSocket server through
subscribeRemoteRuntimeRequest so the throw travels ws 'message' -> handleFrame
-> consumer; without the frame-router guard vitest reports it as an unhandled
error, which is main_uncaught_exception in production.

---------

Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: mmarabel <mmarabel@users.noreply.github.com>
2026-09-25 14:48:54 -07:00

118 lines
3.6 KiB
TypeScript

import { Buffer } from 'node:buffer'
import { describe, expect, it, vi } from 'vitest'
import { encrypt, encryptBytes } from './e2ee-crypto'
import type { RemoteRuntimeClientError } from './remote-runtime-client-error'
import { RemoteRuntimeSubscriptionFrameRouter } from './remote-runtime-subscription-frame-router'
const SHARED_KEY = new Uint8Array(32).fill(7)
function createAwaitingAuthRouter() {
const fail = vi.fn<(error: RemoteRuntimeClientError) => void>()
const router = new RemoteRuntimeSubscriptionFrameRouter<unknown>({
sharedKey: SHARED_KEY,
serializedAuth: '{}',
serializedRequest: '{}',
requestId: 'request-1',
send: vi.fn(),
fail,
onAuthenticated: vi.fn(),
callbacks: { onResponse: vi.fn() }
})
router.state = 'awaiting_authenticated'
return { fail, router }
}
function handleEncryptedAuthFrame(
router: RemoteRuntimeSubscriptionFrameRouter<unknown>,
plaintext: string
): void {
router.handleFrame(Buffer.from(encrypt(plaintext, SHARED_KEY)), false)
}
describe('RemoteRuntimeSubscriptionFrameRouter authentication frames', () => {
it('reports malformed authentication frames as invalid responses', () => {
const { fail, router } = createAwaitingAuthRouter()
handleEncryptedAuthFrame(router, 'not-json')
expect(fail).toHaveBeenCalledOnce()
expect(fail.mock.calls[0][0]).toMatchObject({
code: 'invalid_runtime_response',
message: 'Remote Orca runtime returned an invalid E2EE auth frame.'
})
})
it('reports explicit authentication rejection as a rejected pairing token', () => {
const { fail, router } = createAwaitingAuthRouter()
const rejection = JSON.stringify({
type: 'e2ee_error',
error: { code: 'unauthorized' }
})
handleEncryptedAuthFrame(router, rejection)
expect(fail).toHaveBeenCalledOnce()
expect(fail.mock.calls[0][0]).toMatchObject({
code: 'unauthorized',
message: 'Remote Orca runtime rejected the pairing token.'
})
})
})
function createReadyRouter(callbacks: {
onResponse: (response: unknown) => void
onBinary?: (bytes: Uint8Array) => void
}) {
const fail = vi.fn<(error: RemoteRuntimeClientError) => void>()
const router = new RemoteRuntimeSubscriptionFrameRouter<unknown>({
sharedKey: SHARED_KEY,
serializedAuth: '{}',
serializedRequest: '{}',
requestId: 'request-1',
send: vi.fn(),
fail,
onAuthenticated: vi.fn(),
callbacks
})
router.state = 'ready'
return { fail, router }
}
describe('RemoteRuntimeSubscriptionFrameRouter consumer callbacks', () => {
it('fails the subscription instead of throwing out of the socket message handler', () => {
const { fail, router } = createReadyRouter({
onResponse: () => {
throw new Error('Unknown environment: env-1')
}
})
const response = JSON.stringify({
id: 'request-1',
ok: true,
result: {},
_meta: { runtimeId: 'r' }
})
expect(() => handleEncryptedAuthFrame(router, response)).not.toThrow()
expect(fail).toHaveBeenCalledOnce()
expect(fail.mock.calls[0][0]).toMatchObject({
code: 'runtime_error',
message: 'Unknown environment: env-1'
})
})
it('fails the subscription when a binary consumer throws', () => {
const { fail, router } = createReadyRouter({
onResponse: vi.fn(),
onBinary: () => {
throw new Error('consumer exploded')
}
})
expect(() =>
router.handleFrame(Buffer.from(encryptBytes(new Uint8Array([1, 2, 3]), SHARED_KEY)), true)
).not.toThrow()
expect(fail).toHaveBeenCalledOnce()
expect(fail.mock.calls[0][0]).toMatchObject({ code: 'runtime_error' })
})
})