| 1 | import { describe, expect, it, vi } from 'vitest';
|
| 2 | import {
|
| 3 | resolvePublicRuntimeEndpoint,
|
| 4 | runtimeDeliverySignature,
|
| 5 | } from '../packages/persistence/src/runtime.js';
|
| 6 | import { createOpenClaspRuntimeHandler, type RuntimeDelivery } from '../packages/sdk/src/index.js';
|
| 7 |
|
| 8 | describe('external agent runtime connector', () => {
|
| 9 | const secret = 'runtime-secret-long-enough-for-testing';
|
| 10 |
|
| 11 | it('answers endpoint verification and rejects unsigned delivery', async () => {
|
| 12 | const handler = createOpenClaspRuntimeHandler({ signingSecret: secret, onDelivery: vi.fn() });
|
| 13 | const verification = await handler(
|
| 14 | new Request('https://agent.example/openclasp', {
|
| 15 | method: 'POST',
|
| 16 | body: JSON.stringify({
|
| 17 | type: 'openclasp.runtime.verify',
|
| 18 | version: '1',
|
| 19 | agentId: 'agent-b',
|
| 20 | challenge: 'challenge-1',
|
| 21 | }),
|
| 22 | }),
|
| 23 | );
|
| 24 | await expect(verification.json()).resolves.toEqual({
|
| 25 | type: 'openclasp.runtime.verified',
|
| 26 | version: '1',
|
| 27 | agentId: 'agent-b',
|
| 28 | challenge: 'challenge-1',
|
| 29 | });
|
| 30 | const unauthorized = await handler(
|
| 31 | new Request('https://agent.example/openclasp', { method: 'POST', body: '{}' }),
|
| 32 | );
|
| 33 | expect(unauthorized.status).toBe(401);
|
| 34 | });
|
| 35 |
|
| 36 | it('verifies signed deliveries before invoking the agent runtime', async () => {
|
| 37 | const onDelivery = vi.fn();
|
| 38 | const handler = createOpenClaspRuntimeHandler({ signingSecret: secret, onDelivery });
|
| 39 | const delivery: RuntimeDelivery = {
|
| 40 | type: 'openclasp.a2a.delivery',
|
| 41 | version: '1',
|
| 42 | deliveryId: 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa',
|
| 43 | agentId: 'agent-b',
|
| 44 | interactionId: 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb',
|
| 45 | receivedAt: new Date().toISOString(),
|
| 46 | message: {
|
| 47 | messageId: 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa',
|
| 48 | senderAgentId: 'agent-a',
|
| 49 | contentType: 'application/json',
|
| 50 | createdAt: new Date().toISOString(),
|
| 51 | expiresAt: new Date(Date.now() + 60_000).toISOString(),
|
| 52 | payload: { text: 'hello' },
|
| 53 | },
|
| 54 | reply: {
|
| 55 | endpoint: 'https://openclasp.vercel.app/a2a/agent-a',
|
| 56 | bearerToken: 'scoped-token',
|
| 57 | },
|
| 58 | };
|
| 59 | const body = JSON.stringify(delivery);
|
| 60 | const timestamp = new Date().toISOString();
|
| 61 | const response = await handler(
|
| 62 | new Request('https://agent.example/openclasp', {
|
| 63 | method: 'POST',
|
| 64 | headers: {
|
| 65 | 'openclasp-delivery-id': delivery.deliveryId,
|
| 66 | 'openclasp-timestamp': timestamp,
|
| 67 | 'openclasp-signature': `v1=${runtimeDeliverySignature(secret, delivery.deliveryId, timestamp, body)}`,
|
| 68 | },
|
| 69 | body,
|
| 70 | }),
|
| 71 | );
|
| 72 | expect(response.status).toBe(202);
|
| 73 | expect(onDelivery).toHaveBeenCalledWith(delivery);
|
| 74 | });
|
| 75 | });
|
| 76 | it('rejects local and non-HTTPS runtime targets before connecting', async () => {
|
| 77 | await expect(resolvePublicRuntimeEndpoint('http://example.com/runtime')).rejects.toThrow('HTTPS');
|
| 78 | await expect(resolvePublicRuntimeEndpoint('https://localhost/runtime')).rejects.toThrow(
|
| 79 | 'public DNS',
|
| 80 | );
|
| 81 | await expect(resolvePublicRuntimeEndpoint('https://127.0.0.1/runtime')).rejects.toThrow(
|
| 82 | 'public DNS',
|
| 83 | );
|
| 84 | });
|