ipsambeatae
Version:
Shared dependencies of Compass, the MongoDB extension for VSCode and MongoSH
939 lines (845 loc) • 28.5 kB
text/typescript
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')
);
});
});
});