mirror of
https://github.com/stablyai/orca.git
synced 2026-10-13 00:02:54 +00:00
* 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>
118 lines
3.6 KiB
TypeScript
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' })
|
|
})
|
|
})
|