import { describe, it, expect, vi, beforeEach } from 'vitest';
import { verify } from '../../src/tools/verify.js';
import { sign } from '../../src/crypto/signing.js';
import type { RegistryApiClient } from '../../src/client/api.js';
import { testAgent1, testKeyPair1 } from '../fixtures/keys.js';
describe('tools/verify', () => {
let mockClient: RegistryApiClient;
beforeEach(() => {
mockClient = {
verify: vi.fn(),
} as unknown as RegistryApiClient;
});
describe('registry verification', () => {
it('should verify signature via registry', async () => {
vi.mocked(mockClient.verify).mockResolvedValue({
valid: true,
agent: testAgent1,
key: testAgent1.keys[0],
});
const result = await verify(
{
message: 'Hello, World!',
signature: 'test-signature',
origin: testAgent1.domain!,
},
mockClient
);
expect(mockClient.verify).toHaveBeenCalledWith({
message: 'Hello, World!',
signature: 'test-signature',
origin: testAgent1.domain,
keyId: undefined,
});
expect(result.valid).toBe(true);
expect(result.method).toBe('registry');
expect(result.agent?.id).toBe(testAgent1.id);
expect(result.key?.id).toBe(testAgent1.keys[0]!.id);
});
it('should use specific key ID when provided', async () => {
vi.mocked(mockClient.verify).mockResolvedValue({
valid: true,
agent: testAgent1,
key: testAgent1.keys[0],
});
await verify(
{
message: 'Hello, World!',
signature: 'test-signature',
origin: testAgent1.domain!,
keyId: testAgent1.keys[0]!.id,
},
mockClient
);
expect(mockClient.verify).toHaveBeenCalledWith(
expect.objectContaining({
keyId: testAgent1.keys[0]!.id,
})
);
});
it('should return invalid for bad signature', async () => {
vi.mocked(mockClient.verify).mockResolvedValue({
valid: false,
error: 'Signature verification failed',
});
const result = await verify(
{
message: 'Hello, World!',
signature: 'bad-signature',
origin: testAgent1.domain!,
},
mockClient
);
expect(result.valid).toBe(false);
expect(result.error).toContain('Signature verification failed');
});
it('should handle registry errors', async () => {
vi.mocked(mockClient.verify).mockRejectedValue(new Error('Registry unavailable'));
const result = await verify(
{
message: 'Hello, World!',
signature: 'test-signature',
origin: testAgent1.domain!,
},
mockClient
);
expect(result.valid).toBe(false);
expect(result.method).toBe('registry');
expect(result.error).toContain('Registry unavailable');
});
});
describe('local verification', () => {
it('should verify locally with provided public key', async () => {
const message = 'Hello, World!';
const signature = await sign(message, testKeyPair1.privateKey);
const result = await verify(
{
message,
signature,
origin: testAgent1.domain!,
localOnly: true,
publicKey: testKeyPair1.publicKey,
},
mockClient
);
expect(result.valid).toBe(true);
expect(result.method).toBe('local');
expect(mockClient.verify).not.toHaveBeenCalled();
});
it('should fail local verification without public key', async () => {
const result = await verify(
{
message: 'Hello, World!',
signature: 'test-signature',
origin: testAgent1.domain!,
localOnly: true,
},
mockClient
);
expect(result.valid).toBe(false);
expect(result.method).toBe('local');
expect(result.error).toContain('publicKey is required');
});
it('should fail local verification with wrong public key', async () => {
const message = 'Hello, World!';
const signature = await sign(message, testKeyPair1.privateKey);
const result = await verify(
{
message,
signature,
origin: testAgent1.domain!,
localOnly: true,
publicKey: 'wrongPublicKeyBase64aaaaaaaaaaaaaaaaaaaaaa=',
},
mockClient
);
expect(result.valid).toBe(false);
expect(result.method).toBe('local');
});
it('should fail local verification with tampered message', async () => {
const signature = await sign('Original message', testKeyPair1.privateKey);
const result = await verify(
{
message: 'Tampered message',
signature,
origin: testAgent1.domain!,
localOnly: true,
publicKey: testKeyPair1.publicKey,
},
mockClient
);
expect(result.valid).toBe(false);
expect(result.method).toBe('local');
});
it('should handle invalid signature format', async () => {
const result = await verify(
{
message: 'Hello, World!',
signature: 'not-valid-base64!!!',
origin: testAgent1.domain!,
localOnly: true,
publicKey: testKeyPair1.publicKey,
},
mockClient
);
expect(result.valid).toBe(false);
expect(result.method).toBe('local');
});
});
});