mirror of
https://github.com/stablyai/orca.git
synced 2026-10-22 00:03:47 +00:00
fix(orchestration): defer local mutation identity
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { z } from 'zod'
|
||||
import { RpcDispatcher } from './dispatcher'
|
||||
import { defineMethod, InvalidArgumentError, type RpcRequest } from './core'
|
||||
@@ -37,6 +37,20 @@ const METHODS = [
|
||||
handler: () => {
|
||||
throw new InvalidArgumentError('Async validation rejected payload')
|
||||
}
|
||||
}),
|
||||
defineMethod({
|
||||
name: 'orchestration.inspectCaller',
|
||||
params: z.object({}),
|
||||
handler: (_params, { authenticatedCallerFingerprint }) => ({
|
||||
authenticatedCallerFingerprint
|
||||
})
|
||||
}),
|
||||
defineMethod({
|
||||
name: 'orchestration.federationInspectCaller',
|
||||
params: z.object({}),
|
||||
handler: (_params, { authenticatedCallerFingerprint }) => ({
|
||||
authenticatedCallerFingerprint
|
||||
})
|
||||
})
|
||||
]
|
||||
|
||||
@@ -109,12 +123,16 @@ describe('RpcDispatcher computer-use validation errors', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('maps async validation errors to invalid_argument without shadowing Zod formatting', async () => {
|
||||
it('maps async validation errors over streaming transport without shadowing Zod formatting', async () => {
|
||||
const messages: string[] = []
|
||||
const dispatcher = new RpcDispatcher({ runtime: makeRuntime(), methods: METHODS })
|
||||
|
||||
const response = await dispatcher.dispatch(makeRequest('orchestration.invalidArgument', {}))
|
||||
await dispatcher.dispatchStreaming(
|
||||
makeRequest('orchestration.invalidArgument', {}),
|
||||
(message) => messages.push(message)
|
||||
)
|
||||
|
||||
expect(response).toMatchObject({
|
||||
expect(JSON.parse(messages[0]!)).toMatchObject({
|
||||
ok: false,
|
||||
error: {
|
||||
code: 'invalid_argument',
|
||||
@@ -122,4 +140,35 @@ describe('RpcDispatcher computer-use validation errors', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('forwards a paired caller fingerprint without requiring local orchestration state', async () => {
|
||||
const dispatcher = new RpcDispatcher({ runtime: makeRuntime(), methods: METHODS })
|
||||
|
||||
const response = await dispatcher.dispatch(makeRequest('orchestration.inspectCaller', {}), {
|
||||
authenticatedCallerFingerprint: 'paired-caller'
|
||||
})
|
||||
|
||||
expect(response).toMatchObject({
|
||||
ok: true,
|
||||
result: { authenticatedCallerFingerprint: 'paired-caller' }
|
||||
})
|
||||
})
|
||||
|
||||
it('provides local identity to read-only federation authorization', async () => {
|
||||
const getOrCreateLocalMutationCallerFingerprint = vi.fn(() => 'local-caller')
|
||||
const runtime = Object.assign(makeRuntime(), {
|
||||
getOrchestrationDb: () => ({ getOrCreateLocalMutationCallerFingerprint })
|
||||
})
|
||||
const dispatcher = new RpcDispatcher({ runtime, methods: METHODS })
|
||||
|
||||
const response = await dispatcher.dispatch(
|
||||
makeRequest('orchestration.federationInspectCaller', {})
|
||||
)
|
||||
|
||||
expect(response).toMatchObject({
|
||||
ok: true,
|
||||
result: { authenticatedCallerFingerprint: 'local-caller' }
|
||||
})
|
||||
expect(getOrCreateLocalMutationCallerFingerprint).toHaveBeenCalledOnce()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from './core'
|
||||
|
||||
import type { FeatureInteractionId } from '../../../shared/feature-interactions'
|
||||
import { isOrchestrationMutation } from '../../../shared/orchestration-rpc-contract'
|
||||
import { errorResponse, successResponse } from './errors'
|
||||
import { ALL_RPC_METHODS } from './methods'
|
||||
import { emulatorProbe, emulatorProbeError } from '../../emulator/emulator-probe'
|
||||
@@ -93,7 +94,7 @@ export class RpcDispatcher {
|
||||
)
|
||||
const authenticatedCallerFingerprint =
|
||||
options?.authenticatedCallerFingerprint ??
|
||||
(request.method.startsWith('orchestration.')
|
||||
(needsLocalCallerFingerprint(request, effectiveParams)
|
||||
? this.orchestrationMutations.getLocalAuthenticatedCallerFingerprint()
|
||||
: undefined)
|
||||
const invoke = (mutation?: DurableMutationInvocation) => {
|
||||
@@ -186,7 +187,7 @@ export class RpcDispatcher {
|
||||
)
|
||||
const authenticatedCallerFingerprint =
|
||||
options?.authenticatedCallerFingerprint ??
|
||||
(request.method.startsWith('orchestration.')
|
||||
(needsLocalCallerFingerprint(request, effectiveParams)
|
||||
? this.orchestrationMutations.getLocalAuthenticatedCallerFingerprint()
|
||||
: undefined)
|
||||
const invoke = (mutation?: DurableMutationInvocation) => {
|
||||
@@ -303,3 +304,10 @@ export class RpcDispatcher {
|
||||
return { runtimeId: this.runtime.getRuntimeId() }
|
||||
}
|
||||
}
|
||||
|
||||
function needsLocalCallerFingerprint(request: RpcRequest, params: unknown): boolean {
|
||||
return (
|
||||
request.method.startsWith('orchestration.federation') ||
|
||||
(!!request.orchestrationRequestId && isOrchestrationMutation(request.method, params))
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user