67 lines
3.6 KiB
TypeScript
67 lines
3.6 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest';
|
|
import { NvdCveClient, NvdCveClientError, parseNvdCveResponse } from '../../server/cve/nvd-cve-client';
|
|
|
|
const payload = {
|
|
version: '2.0',
|
|
vulnerabilities: [{ cve: {
|
|
id: 'CVE-2012-3037', sourceIdentifier: 'nvd@nist.gov', published: '2012-08-25T10:55:01.000',
|
|
lastModified: '2025-04-11T00:51:21.963', vulnStatus: 'Deferred',
|
|
descriptions: [{ lang: 'en', value: 'Synthetic vulnerability description.' }],
|
|
metrics: {
|
|
cvssMetricV31: [{ source: 'nvd@nist.gov', type: 'Primary', exploitabilityScore: 3.9, impactScore: 5.9,
|
|
cvssData: { version: '3.1', vectorString: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H', baseScore: 9.8, baseSeverity: 'CRITICAL' } }],
|
|
cvssMetricV2: [{ source: 'nvd@nist.gov', type: 'Primary', baseSeverity: 'MEDIUM', exploitabilityScore: 8.6, impactScore: 2.9,
|
|
cvssData: { version: '2.0', vectorString: 'AV:N/AC:M/Au:N/C:P/I:N/A:N', baseScore: 4.3 } }]
|
|
},
|
|
weaknesses: [{ source: 'nvd@nist.gov', type: 'Primary', description: [{ lang: 'en', value: 'CWE-119' }] }],
|
|
references: [{ url: 'https://vendor.example/advisory', source: 'nvd@nist.gov', tags: ['Vendor Advisory', 'Patch'] }],
|
|
configurations: [{ operator: 'AND', nodes: [
|
|
{ cpeMatch: [{
|
|
vulnerable: true, criteria: 'cpe:2.3:a:vendor:product:*:*:*:*:*:*:*:*', versionEndExcluding: '2.0'
|
|
}] },
|
|
{ cpeMatch: [{ vulnerable: false, criteria: 'cpe:2.3:h:vendor:device:*:*:*:*:*:*:*:*' }] }
|
|
] }],
|
|
cisaRequiredAction: 'Apply vendor guidance.'
|
|
} }]
|
|
};
|
|
|
|
describe('NVD CVE enrichment', () => {
|
|
it('normalizes the bounded NVD 2.0 response into shared CVE knowledge', () => {
|
|
const record = parseNvdCveResponse(payload, 'CVE-2012-3037', '2026-09-10T08:00:00.000Z');
|
|
expect(record).toMatchObject({
|
|
cveId: 'CVE-2012-3037', source: 'nvd', description: 'Synthetic vulnerability description.',
|
|
metrics: [
|
|
{ version: '3.1', baseScore: 9.8, baseSeverity: 'CRITICAL' },
|
|
{ version: '2.0', baseScore: 4.3, baseSeverity: 'MEDIUM' }
|
|
],
|
|
weaknesses: [{ id: 'CWE-119' }],
|
|
references: [{ url: 'https://vendor.example/advisory', tags: ['Vendor Advisory', 'Patch'] }],
|
|
affectedConfigurations: [{
|
|
operator: 'AND',
|
|
vulnerableMatches: [{ criteria: 'cpe:2.3:a:vendor:product:*:*:*:*:*:*:*:*', versionEndExcluding: '2.0' }],
|
|
runningOnWith: [{ criteria: 'cpe:2.3:h:vendor:device:*:*:*:*:*:*:*:*' }]
|
|
}],
|
|
attributes: { cisaRequiredAction: 'Apply vendor guidance.' }
|
|
});
|
|
});
|
|
|
|
it('calls only the fixed NVD endpoint with an encoded exact CVE and optional API key', async () => {
|
|
const fetcher = vi.fn<typeof fetch>().mockResolvedValue(new Response(JSON.stringify(payload), {
|
|
status: 200, headers: { 'Content-Type': 'application/json' }
|
|
}));
|
|
const client = new NvdCveClient({ fetcher, apiKey: 'test-key', now: () => new Date('2026-09-10T08:00:00.000Z') });
|
|
await expect(client.fetchCve('cve-2012-3037')).resolves.toMatchObject({ cveId: 'CVE-2012-3037' });
|
|
const url = fetcher.mock.calls[0][0] as URL;
|
|
expect(url.origin + url.pathname).toBe('https://services.nvd.nist.gov/rest/json/cves/2.0');
|
|
expect(url.searchParams.get('cveId')).toBe('CVE-2012-3037');
|
|
expect(new Headers(fetcher.mock.calls[0][1]?.headers).get('apiKey')).toBe('test-key');
|
|
});
|
|
|
|
it('rejects invalid identifiers before making a network request', async () => {
|
|
const fetcher = vi.fn<typeof fetch>();
|
|
const client = new NvdCveClient({ fetcher });
|
|
await expect(client.fetchCve('not-a-cve')).rejects.toMatchObject({ code: 'invalid_cve_id' } satisfies Partial<NvdCveClientError>);
|
|
expect(fetcher).not.toHaveBeenCalled();
|
|
});
|
|
});
|