|
1 | 1 | /** |
2 | 2 | * @vitest-environment node |
3 | 3 | */ |
| 4 | +import { inputValidationMock, inputValidationMockFns } from '@sim/testing' |
4 | 5 | import { describe, expect, it, vi } from 'vitest' |
5 | 6 |
|
| 7 | +vi.mock('@/lib/core/security/input-validation.server', () => inputValidationMock) |
| 8 | + |
6 | 9 | /** |
7 | 10 | * Only this service's configs are needed; the full registry is ~6,000 modules. |
8 | 11 | * Registration is asserted through the generated `@/tools/tool-ids`. |
@@ -484,28 +487,42 @@ describe('pitchbook error extraction', () => { |
484 | 487 | * not appear anywhere in the tool result, message or retained body. |
485 | 488 | */ |
486 | 489 | it('keeps the rejected key out of the whole failed tool result', async () => { |
487 | | - const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue( |
488 | | - new Response( |
489 | | - JSON.stringify({ |
490 | | - reason: 'UNAUTHORIZED', |
491 | | - message: `Active API key ${SUBMITTED_KEY} not found`, |
492 | | - }), |
493 | | - { status: 401, headers: { 'content-type': 'application/json' } } |
494 | | - ) |
| 490 | + const response = new Response( |
| 491 | + JSON.stringify({ |
| 492 | + reason: 'UNAUTHORIZED', |
| 493 | + message: `Active API key ${SUBMITTED_KEY} not found`, |
| 494 | + }), |
| 495 | + { status: 401, headers: { 'content-type': 'application/json' } } |
495 | 496 | ) |
| 497 | + inputValidationMockFns.mockValidateUrlWithDNS.mockResolvedValueOnce({ |
| 498 | + isValid: true, |
| 499 | + resolvedIP: '93.184.216.34', |
| 500 | + }) |
| 501 | + inputValidationMockFns.mockSecureFetchWithPinnedIP.mockResolvedValueOnce({ |
| 502 | + ok: response.ok, |
| 503 | + status: response.status, |
| 504 | + statusText: response.statusText, |
| 505 | + headers: { |
| 506 | + get: (name: string) => response.headers.get(name), |
| 507 | + toRecord: () => Object.fromEntries(response.headers.entries()), |
| 508 | + }, |
| 509 | + body: response.body, |
| 510 | + text: () => response.text(), |
| 511 | + json: () => response.json(), |
| 512 | + arrayBuffer: () => response.arrayBuffer(), |
| 513 | + }) |
496 | 514 |
|
497 | | - try { |
498 | | - const result = await executeTool('pitchbook_company_bio', { |
499 | | - apiKey: SUBMITTED_KEY, |
500 | | - pbId: '10618-03', |
501 | | - }) |
502 | | - |
503 | | - expect(result.success).toBe(false) |
504 | | - expect(JSON.stringify(result.output ?? {})).not.toContain(SUBMITTED_KEY) |
505 | | - expect(result.error ?? '').not.toContain(SUBMITTED_KEY) |
506 | | - } finally { |
507 | | - fetchSpy.mockRestore() |
508 | | - } |
| 515 | + const result = await executeTool('pitchbook_company_bio', { |
| 516 | + apiKey: SUBMITTED_KEY, |
| 517 | + pbId: '10618-03', |
| 518 | + }) |
| 519 | + |
| 520 | + expect(inputValidationMockFns.mockSecureFetchWithPinnedIP).toHaveBeenCalledOnce() |
| 521 | + expect(result.success).toBe(false) |
| 522 | + expect(result.error).toBe( |
| 523 | + 'PitchBook rejected the API key. Check that the key is active and has API access.' |
| 524 | + ) |
| 525 | + expect(JSON.stringify(result)).not.toContain(SUBMITTED_KEY) |
509 | 526 | }) |
510 | 527 |
|
511 | 528 | it('routes every pitchbook tool through the scrubbing extractor', () => { |
|
0 commit comments