fix(typert): harden remote reflection boundaries

This commit is contained in:
imccyu
2026-08-06 17:49:35 +08:00
parent 88385a658e
commit 9b63d72c94
28 changed files with 813 additions and 116 deletions
+14 -1
View File
@@ -204,7 +204,13 @@ describe('Client TypeRT API', () => {
})
it('rejects duplicate, live, scoped-service, and Context namespace collisions', async () => {
const ctx = await bench(vi.fn<ConnectionHandle['rpc']['call']>())
const call = vi.fn<ConnectionHandle['rpc']['call']>()
.mockResolvedValue({ ok: true, value: { renamed: true } })
const ctx = await bench(call)
const agentCtx = ctx.extend({ fixtureId: 'agent-remounted' }) as FixtureContext
ctx.typert.contexts.registerClient('fixture', {
identity: candidate => (candidate as Context & { fixtureId?: string }).fixtureId,
})
const direct = directDescriptor()
const context = contextDescriptor()
@@ -242,6 +248,13 @@ describe('Client TypeRT API', () => {
package: '@fixture/multiple-scoped',
descriptors: [directDescriptor(), contextDescriptor()],
})
await expect(agentCtx.goals.rename({ objective: 'remounted' })).resolves.toEqual({ renamed: true })
expect(call).toHaveBeenLastCalledWith(
'/api',
'goals/rename',
{ args: { agentId: 'agent-remounted', request: { objective: 'remounted' } } },
expect.any(AbortSignal),
)
await disposeMultipleScoped()
})
@@ -370,6 +370,19 @@ describe('TypertGatewayService', () => {
})).resolves.toEqual({ agentId: 'agent-1', title: 'ship', scope: 'direct-src' })
})
it('does not downgrade an observed SRC lookup after its provider unloads', async () => {
const { ctx, service } = await setup()
const dispose = registerAgentLookup(ctx, { id: 'agent-1' })
await dispose()
await expectCode(ctx.typertGateway.invoke({
namespace: 'goals',
method: 'create',
args: { agentId: 'agent-1', request: { title: 'ship' } },
}), 'lookup-unavailable')
expect(service.calls).toEqual([])
})
it('derives SRC Remote Context identity and preserves the scoped Proxy receiver', async () => {
const { ctx } = await setup()
const scoped = ctx.extend({ fixtureScope: 'agent-src' })
@@ -657,6 +670,22 @@ describe('TypertGatewayService', () => {
}), 'result-invalid')
})
it('rejects non-JSON values after strict codec validation', async () => {
const { ctx, service } = await setup()
const descriptor = strictOnlyDescriptor()
registerStrict(ctx, [{
...descriptor,
result: strictCodec('@fixture/gateway#UnknownResult', z.unknown()),
}])
service.nextResult = 1n
await expectCode(ctx.typertGateway.invoke({
namespace: 'goals',
method: 'strictOnly',
args: { request: { title: 'ship' } },
}), 'result-invalid')
})
it.each([
undefined,
Number.NaN,