UNPKG

ipsambeatae

Version:

Shared dependencies of Compass, the MongoDB extension for VSCode and MongoSH

939 lines (845 loc) 28.5 kB
import path from 'path'; import type { SinonFakeTimers } from 'sinon'; import sinon, { useFakeTimers } from 'sinon'; import { generateVulnerabilityReport } from './generate-vulnerability-report'; import { withTempDir, importFixture } from '../../test/helpers'; import { expect } from 'chai'; import type { KnownSeverity } from '../vulnerability'; import { vulnerabilityToSnyk } from '../vulnerability'; import nock from 'nock'; async function runGenerateReport( structure: Record<string, string>, options: { failOn?: KnownSeverity; createJiraIssues?: boolean } = {} ) { return withTempDir(structure, async (tempDir) => { let output = ''; const error = await generateVulnerabilityReport({ dependencyFiles: [path.resolve(tempDir, 'dependencies.json')], snykReports: [path.resolve(tempDir, 'snyk-report.json')], snykPolicyPath: '.snyk' in structure ? path.resolve(tempDir, '.snyk') : undefined, failOn: options.failOn, createJiraIssues: options.createJiraIssues, printResult: (result) => { output = result; }, }).catch((err) => Promise.resolve(err)); return { error, output }; }); } describe('generate-vulnerability-report', function () { it('reports an empty table if nothing matches', async function () { const { error, output } = await runGenerateReport({ '.snyk': '', 'dependencies.json': JSON.stringify([{ name: 'pkg1', version: '1.0.0' }]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [{}] }), }); expect(error).to.be.undefined; expect(output).to.equal(`## Vulnerabilities Report (0 vulnerabilities) | dep@version | id | score | fixed in | ignored | | ----------- | -- | ----- | -------- | ------- | `); }); it('reports an entry table if a vulnerability applies', async function () { const { error, output } = await runGenerateReport({ '.snyk': '', 'dependencies.json': JSON.stringify([{ name: 'pkg1', version: '1.0.0' }]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'low', score: 0.1, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }), ], }), }); expect(error).to.be.undefined; expect(output).to.equal(`## Vulnerabilities Report (1 vulnerabilities) | dep@version | id | score | fixed in | ignored | | ----------- | -- | ----- | -------- | ------- | | pkg1@1.0.0 | v1 | 0.1 (Low) | 2.0.0 | - | `); }); it('sorts vulnerabilities by severity', async function () { const { error, output } = await runGenerateReport({ '.snyk': '', 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, { name: 'pkg1', version: '1.5.0' }, { name: 'pkg2', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'low', score: 0.1, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }), vulnerabilityToSnyk({ id: 'v2', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'critical', score: 10, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.5.0', }), vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'medium', score: 5, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg2', packageVersion: '1.0.0', }), ], }), }); expect(error).to.be.undefined; expect(output).to.equal(`## Vulnerabilities Report (3 vulnerabilities) | dep@version | id | score | fixed in | ignored | | ----------- | -- | ----- | -------- | ------- | | pkg1@1.5.0 | v2 | 10 (Critical) | 2.0.0 | - | | pkg2@1.0.0 | v1 | 5 (Medium) | 2.0.0 | - | | pkg1@1.0.0 | v1 | 0.1 (Low) | 2.0.0 | - | `); }); it('fails if severity is >= failOn', async function () { const { error, output } = await runGenerateReport( { '.snyk': '', 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'low', score: 0.1, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }), ], }), }, { failOn: 'low' } ); expect(error?.message).to.equal( 'Vulnerabilities check failed: found vulnerabilities >= "low"' ); expect(output).to.equal(`## Vulnerabilities Report (1 vulnerabilities) | dep@version | id | score | fixed in | ignored | | ----------- | -- | ----- | -------- | ------- | | pkg1@1.0.0 | v1 | 0.1 (Low) | 2.0.0 | - | `); }); it('fails if severity unknown', async function () { const { error, output } = await runGenerateReport( { '.snyk': '', 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'unknown', score: undefined, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }), ], }), }, { failOn: 'low' } ); expect(error?.message).to.equal( 'Vulnerabilities check failed: found vulnerabilities >= "low"' ); expect(output).to.equal(`## Vulnerabilities Report (1 vulnerabilities) | dep@version | id | score | fixed in | ignored | | ----------- | -- | ----- | -------- | ------- | | pkg1@1.0.0 | v1 | ? (Unknown) | 2.0.0 | - | `); }); it('auto-ignores vulnerabilities without remediation', async function () { const { error, output } = await runGenerateReport( { '.snyk': '', 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'critical', score: 10, vulnerableSemver: '<=2.0.0', fixedIn: [], packageName: 'pkg1', packageVersion: '1.0.0', }), ], }), }, { failOn: 'low' } ); expect(error?.message).to.be.undefined; expect(output).to.equal(`## Vulnerabilities Report (1 vulnerabilities) | dep@version | id | score | fixed in | ignored | | ----------- | -- | ----- | -------- | ------- | | pkg1@1.0.0 | v1 | 10 (Critical) | N/A | Reason: Remediation not available yet | `); }); it('allows to ignore vulnerabilities with a snyk policy', async function () { const { error, output } = await runGenerateReport( { '.snyk': `# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. version: v1.25.0 # ignores vulnerabilities until expiry date; change duration by modifying expiry date ignore: v1: - '*': reason: None Given expires: 3000-06-19T16:42:35.740Z created: 2023-05-20T16:42:35.746Z patch: {} `, 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'critical', score: 10, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }), ], }), }, { failOn: 'low' } ); expect(error?.message).to.be.undefined; expect(output).to.equal(`## Vulnerabilities Report (1 vulnerabilities) | dep@version | id | score | fixed in | ignored | | ----------- | -- | ----- | -------- | ------- | | pkg1@1.0.0 | v1 | 10 (Critical) | 2.0.0 | Reason: None Given | `); }); it('allows to ignore unknown severity', async function () { const { error, output } = await runGenerateReport( { '.snyk': `# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. version: v1.25.0 # ignores vulnerabilities until expiry date; change duration by modifying expiry date ignore: v1: - '*': reason: None Given expires: 3000-06-19T16:42:35.740Z created: 2023-05-20T16:42:35.746Z patch: {} `, 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'unknown', score: undefined, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }), ], }), }, { failOn: 'low' } ); expect(error?.message).to.be.undefined; expect(output).to.equal(`## Vulnerabilities Report (1 vulnerabilities) | dep@version | id | score | fixed in | ignored | | ----------- | -- | ----- | -------- | ------- | | pkg1@1.0.0 | v1 | ? (Unknown) | 2.0.0 | Reason: None Given | `); }); it('fails with expired policies', async function () { const { error, output } = await runGenerateReport( { '.snyk': `# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. version: v1.25.0 # ignores vulnerabilities until expiry date; change duration by modifying expiry date ignore: v1: - '*': reason: None Given expires: 2022-06-19T16:42:35.740Z created: 2022-05-20T16:42:35.746Z patch: {} `, 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'critical', score: 10, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }), ], }), }, { failOn: 'low' } ); expect(error?.message).to.equal( 'Vulnerabilities check failed: found vulnerabilities >= "low"' ); expect(output).to.equal(`## Vulnerabilities Report (1 vulnerabilities) | dep@version | id | score | fixed in | ignored | | ----------- | -- | ----- | -------- | ------- | | pkg1@1.0.0 | v1 | 10 (Critical) | 2.0.0 | Reason: None Given (Expired) | `); }); it('works with the result of scan-node-js', async function () { const { error, output } = await runGenerateReport( { '.snyk': '', 'dependencies.json': JSON.stringify([ { name: '.node.js', version: '16.19.1' }, ]), 'snyk-report.json': JSON.stringify( await importFixture('expect-unknown.json') ), }, { failOn: 'low' } ); expect(error?.message).to.equal( 'Vulnerabilities check failed: found vulnerabilities >= "low"' ); expect(output).to.equal(`## Vulnerabilities Report (3 vulnerabilities) | dep@version | id | score | fixed in | ignored | | ----------- | -- | ----- | -------- | ------- | | .node.js@16.19.1 | NSWG-COR-99 | ? (Unknown) | ^14.20.0, ^16.20.0, ^18.9.1 | - | | .node.js@16.19.1 | NSWG-COR-98 | 7.3 (High) | ^14.20.0, ^16.20.0, ^18.5.0 | - | | .node.js@16.19.1 | NSWG-COR-95 | 6.5 (Medium) | ^14.20.0, ^16.20.0, ^18.5.0 | - | `); }); describe('createJiraIssues', function () { const envBackup = { ...process.env }; const mockJiraSearchApi = ( pkg: string, vulnId: string, { expired } = { expired: false } ) => { return nock('https://jira.example.com') .get('/rest/api/2/search') .matchHeader( 'authorization', `Bearer ${process.env.JIRA_API_TOKEN ?? ''}` ) .query({ jql: `project="MY-PROJECT" AND issuetype="Build Failure" AND resolution=Unresolved AND summary~"Vulnerability ${vulnId} found on ${pkg}${ expired ? ' (Policy Expired)' : '' }"`, }); }; const mockCreateIssueApi = (fn: (any) => void) => { return nock('https://jira.example.com') .post('/rest/api/2/issue/', (_body: any) => { fn(_body); return true; }) .matchHeader( 'authorization', `Bearer ${process.env.JIRA_API_TOKEN ?? ''}` ); }; let clock: SinonFakeTimers; beforeEach(function () { process.env.JIRA_BASE_URL = 'https://jira.example.com'; process.env.JIRA_API_TOKEN = 'tok123'; process.env.JIRA_PROJECT = 'MY-PROJECT'; delete process.env.JIRA_VULNERABILITY_BUILD_INFO; clock = useFakeTimers(new Date('2023-01-01T12:00:00.468Z')); }); afterEach(function () { clock.restore(); [ 'JIRA_BASE_URL', 'JIRA_API_TOKEN', 'JIRA_PROJECT', 'JIRA_VULNERABILITY_BUILD_INFO', ].forEach((k) => { if (k in envBackup) { process.env[k] = envBackup[k]; } else { delete process.env[k]; } }); nock.cleanAll(); }); it('trows an error if there are missing env vars', async function () { process.env.JIRA_BASE_URL = ''; const { error } = await runGenerateReport( { 'dependencies.json': JSON.stringify([]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [], }), }, { createJiraIssues: true } ); expect(error?.message).to.equal( 'Missing required variables to create Jira tickets: JIRA_BASE_URL' ); }); it('creates a ticket if does not exist', async function () { mockJiraSearchApi('pkg1@1.0.0', 'v1').reply(200, { total: 0 }); const createIssue = sinon.spy(); mockCreateIssueApi(createIssue).reply(200, { key: 'TICKET-123' }); const { error } = await runGenerateReport( { '.snyk': '', 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: ['x > y > z'], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'low', score: 0.1, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }), ], }), }, { createJiraIssues: true } ); expect(error?.message).to.be.undefined; expect(createIssue).to.have.been.calledOnceWith({ fields: { project: { key: 'MY-PROJECT' }, summary: 'Vulnerability v1 found on pkg1@1.0.0', description: `h4. Vulnerability Details - *Affected Package*: pkg1 - *Affected Version*: 1.0.0 - *Fixed In*: 2.0.0 - *Severity*: low - *Cvss score*: 0.1 h4. Vulnerability Description {panel:title=v1} Vulnerability description {panel} h4. Vulnerable Paths # {{x > y > z}} h4. Links - [v1|https://security.snyk.io/vuln/v1] - [pkg1@1.0.0 vulnerabilities|https://security.snyk.io/package/npm/pkg1/1.0.0] - [CVE-1|https://nvd.nist.gov/vuln/detail/CVE-1] `, issuetype: { name: 'Build Failure' }, components: [{ name: 'Vulnerability Management' }], priority: { name: 'Minor - P4' }, duedate: '2023-03-26', }, }); }); it('creates a ticket and truncates origins if > 10', async function () { mockJiraSearchApi('pkg1@1.0.0', 'v1').reply(200, { total: 0 }); const createIssue = sinon.spy(); mockCreateIssueApi(createIssue).reply(200, { key: 'TICKET-123' }); const { error } = await runGenerateReport( { '.snyk': '', 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: new Array(11).fill('').map((_, i) => vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [`path ${i + 1}`], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'low', score: 0.1, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }) ), }), }, { createJiraIssues: true } ); expect(error?.message).to.be.undefined; expect(createIssue).to.have.been.calledOnceWith({ fields: { project: { key: 'MY-PROJECT' }, summary: 'Vulnerability v1 found on pkg1@1.0.0', description: `h4. Vulnerability Details - *Affected Package*: pkg1 - *Affected Version*: 1.0.0 - *Fixed In*: 2.0.0 - *Severity*: low - *Cvss score*: 0.1 h4. Vulnerability Description {panel:title=v1} Vulnerability description {panel} h4. Vulnerable Paths # {{path 1}} # {{path 2}} # {{path 3}} # {{path 4}} # {{path 5}} # {{path 6}} # {{path 7}} # {{path 8}} # {{path 9}} # {{path 10}} # and other 1 vulnerable path. h4. Links - [v1|https://security.snyk.io/vuln/v1] - [pkg1@1.0.0 vulnerabilities|https://security.snyk.io/package/npm/pkg1/1.0.0] - [CVE-1|https://nvd.nist.gov/vuln/detail/CVE-1] `, issuetype: { name: 'Build Failure' }, components: [{ name: 'Vulnerability Management' }], priority: { name: 'Minor - P4' }, duedate: '2023-03-26', }, }); }); it('creates a ticket with build info if present', async function () { mockJiraSearchApi('pkg1@1.0.0', 'v1').reply(200, { total: 0 }); const createIssue = sinon.spy(); mockCreateIssueApi(createIssue).reply(200, { key: 'TICKET-123' }); process.env.JIRA_VULNERABILITY_BUILD_INFO = `- commit: ...`; const { error } = await runGenerateReport( { '.snyk': '', 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: ['x > y > z'], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'low', score: 0.1, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }), ], }), }, { createJiraIssues: true } ); expect(createIssue).to.have.been.calledOnceWith({ fields: { project: { key: 'MY-PROJECT' }, summary: 'Vulnerability v1 found on pkg1@1.0.0', description: `h4. Vulnerability Details - *Affected Package*: pkg1 - *Affected Version*: 1.0.0 - *Fixed In*: 2.0.0 - *Severity*: low - *Cvss score*: 0.1 h4. Vulnerability Description {panel:title=v1} Vulnerability description {panel} h4. Vulnerable Paths # {{x > y > z}} h4. Links - [v1|https://security.snyk.io/vuln/v1] - [pkg1@1.0.0 vulnerabilities|https://security.snyk.io/package/npm/pkg1/1.0.0] - [CVE-1|https://nvd.nist.gov/vuln/detail/CVE-1] h4. Build Info - commit: ... `, issuetype: { name: 'Build Failure' }, components: [{ name: 'Vulnerability Management' }], priority: { name: 'Minor - P4' }, duedate: '2023-03-26', }, }); expect(error?.message).to.be.undefined; }); it('does not create a ticket if exists', async function () { mockJiraSearchApi('pkg1@1.0.0', 'v1').reply(200, { total: 1 }); const createIssue = sinon.spy(); mockCreateIssueApi(createIssue).reply(200, { key: 'TICKET-123' }); const { error } = await runGenerateReport( { '.snyk': '', 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'low', score: 0.1, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }), ], }), }, { createJiraIssues: true } ); expect(error?.message).to.be.undefined; expect(createIssue).to.not.have.been.called; }); it('does not create a ticket if the vulnerability is ignored', async function () { mockJiraSearchApi('pkg1@1.0.0', 'v1').reply(200, { total: 0 }); const createIssue = sinon.spy(); mockCreateIssueApi(createIssue).reply(200, { key: 'TICKET-123' }); const { error } = await runGenerateReport( { '.snyk': `# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. version: v1.25.0 # ignores vulnerabilities until expiry date; change duration by modifying expiry date ignore: v1: - '*': reason: None Given expires: 3000-06-19T16:42:35.740Z created: 2023-05-20T16:42:35.746Z patch: {} `, 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'low', score: 0.1, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }), ], }), }, { createJiraIssues: true } ); expect(error?.message).to.be.undefined; expect(createIssue).to.not.have.been.called; }); it('creates a policy expired ticket', async function () { mockJiraSearchApi('pkg1@1.0.0', 'v1', { expired: true }).reply(200, { total: 0, }); const createIssue = sinon.spy(); mockCreateIssueApi(createIssue).reply(200, { key: 'TICKET-123' }); const { error } = await runGenerateReport( { '.snyk': `# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. version: v1.25.0 # ignores vulnerabilities until expiry date; change duration by modifying expiry date ignore: v1: - '*': reason: None Given expires: 2000-06-19T16:42:35.740Z created: 2023-05-20T16:42:35.746Z patch: {} `, 'dependencies.json': JSON.stringify([ { name: 'pkg1', version: '1.0.0' }, ]), 'snyk-report.json': JSON.stringify({ vulnerabilities: [ vulnerabilityToSnyk({ id: 'v1', cves: ['CVE-1'], origins: [], title: 'Vulnerability title', description: 'Vulnerability description', urls: [], severity: 'low', score: 0.1, vulnerableSemver: '<=2.0.0', fixedIn: ['2.0.0'], packageName: 'pkg1', packageVersion: '1.0.0', }), ], }), }, { createJiraIssues: true } ); expect(error?.message).to.be.undefined; expect(createIssue).to.have.been.calledOnceWith({ fields: { project: { key: 'MY-PROJECT' }, summary: 'Vulnerability v1 found on pkg1@1.0.0 (Policy Expired)', description: `h4. Vulnerability Details - *Affected Package*: pkg1 - *Affected Version*: 1.0.0 - *Fixed In*: 2.0.0 - *Severity*: low - *Cvss score*: 0.1 h4. Vulnerability Description {panel:title=v1} Vulnerability description {panel} h4. Vulnerable Paths # {{pkg1@1.0.0}} h4. Links - [v1|https://security.snyk.io/vuln/v1] - [pkg1@1.0.0 vulnerabilities|https://security.snyk.io/package/npm/pkg1/1.0.0] - [CVE-1|https://nvd.nist.gov/vuln/detail/CVE-1] `, issuetype: { name: 'Build Failure' }, components: [{ name: 'Vulnerability Management' }], priority: { name: 'Minor - P4' }, duedate: '2023-03-26', }, }); }); it('works with a real example', async function () { mockJiraSearchApi('request@2.88.2', 'SNYK-JS-REQUEST-3361831').reply( 200, { total: 0, } ); const createIssue = sinon.spy(); mockCreateIssueApi(createIssue).reply(200, { key: 'TICKET-123' }); const { error } = await runGenerateReport( { 'dependencies.json': JSON.stringify([ { name: 'request', version: '2.88.2' }, ]), 'snyk-report.json': JSON.stringify( await importFixture('snyk-test.json') ), }, { createJiraIssues: true } ); expect(error?.message).to.be.undefined; expect(createIssue).to.have.been.calledOnceWith( await importFixture('expected-jira-ticket.json') ); }); }); });