Skip to content

Commit

Permalink
feat: add reachable vulns to the snyk test summary line
Browse files Browse the repository at this point in the history
If reachable vulns data is present we gonna present it on the
summary line.
  • Loading branch information
Dar Malovani committed Apr 28, 2020
1 parent b1d0311 commit 3487ca5
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 14 deletions.
18 changes: 17 additions & 1 deletion src/cli/commands/test/formatters/format-reachability.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as wrap from 'wrap-ansi';
import chalk from 'chalk';

import { REACHABILITY } from '../../../../lib/snyk-test/legacy';
import { AnnotatedIssue, REACHABILITY } from '../../../../lib/snyk-test/legacy';

const reachabilityLevels: {
[key in REACHABILITY]: { color: Function; text: string };
Expand Down Expand Up @@ -43,3 +43,19 @@ export function getReachabilityText(reachability?: REACHABILITY): string {
const reachableInfo = reachabilityLevels[reachability];
return reachableInfo ? reachableInfo.text : '';
}

export function summariseReachableVulns(
vulnerabilities: AnnotatedIssue[],
): string {
const reachableVulnsCount = vulnerabilities.filter(
(v) => v.reachability === REACHABILITY.FUNCTION,
).length;

if (reachableVulnsCount > 0) {
const vulnText =
reachableVulnsCount === 1 ? 'vulnerability' : 'vulnerabilities';
return `In addition, found ${reachableVulnsCount} ${vulnText} with a reachable path.`;
}

return '';
}
2 changes: 2 additions & 0 deletions src/cli/commands/test/formatters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ export {
formatIssuesWithRemediation,
getSeverityValue,
} from './remediation-based-format-issues';
export { summariseReachableVulns } from './format-reachability';

export * from './docker';
31 changes: 21 additions & 10 deletions src/cli/commands/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,40 @@ import * as snyk from '../../../lib';
import * as config from '../../../lib/config';
import { isCI } from '../../../lib/is-ci';
import { apiTokenExists } from '../../../lib/api-token';
import { SEVERITIES, FAIL_ON, FailOn } from '../../../lib/snyk-test/common';
import { FAIL_ON, FailOn, SEVERITIES } from '../../../lib/snyk-test/common';
import * as Debug from 'debug';
import {
Options,
TestOptions,
ShowVulnPaths,
SupportedProjectTypes,
TestOptions,
} from '../../../lib/types';
import { isLocalFolder } from '../../../lib/detect';
import { MethodArgs } from '../../args';
import {
GroupedVuln,
LegacyVulnApiResult,
SEVERITY,
GroupedVuln,
VulnMetaData,
TestResult,
VulnMetaData,
} from '../../../lib/snyk-test/legacy';
import {
WIZARD_SUPPORTED_PACKAGE_MANAGERS,
SupportedPackageManagers,
WIZARD_SUPPORTED_PACKAGE_MANAGERS,
} from '../../../lib/package-managers';

import * as analytics from '../../../lib/analytics';
import { FailOnError } from '../../../lib/errors/fail-on-error.ts';
import {
summariseVulnerableResults,
summariseErrorResults,
formatTestMeta,
dockerRemediationForDisplay,
formatDockerBinariesIssues,
formatIssues,
formatIssuesWithRemediation,
formatDockerBinariesIssues,
formatTestMeta,
getSeverityValue,
summariseErrorResults,
summariseReachableVulns,
summariseVulnerableResults,
} from './formatters';

const debug = Debug('snyk-test');
Expand Down Expand Up @@ -448,7 +449,17 @@ function getDisplayedOutput(
} else {
vulnCountText += '.';
}
const summary = testedInfoText + ', ' + chalk.red.bold(vulnCountText);

const reachableVulnsText =
options.reachableVulns && vulnCount > 0
? ` ${summariseReachableVulns(res.vulnerabilities)}`
: '';

const summary =
testedInfoText +
', ' +
chalk.red.bold(vulnCountText) +
chalk.blue.bold(reachableVulnsText);
let wizardAdvice = '';

if (
Expand Down
9 changes: 7 additions & 2 deletions test/acceptance/display-test-results.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as tap from 'tap';
import * as sinon from 'sinon';
import * as _ from 'lodash';
import * as fs from 'fs';

// tslint:disable-next-line:no-var-requires
Expand Down Expand Up @@ -100,9 +99,15 @@ test('test reachability info is displayed', async (t) => {
);
const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse);
try {
await snykTest('maven-app');
await snykTest('maven-app', {
reachableVulns: true,
});
} catch (error) {
const { message } = error;
t.match(
message,
' In addition, found 1 vulnerability with a reachable path.',
);
t.match(message, '[Likely reachable]');
}

Expand Down
72 changes: 71 additions & 1 deletion test/reachable-vulns.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import * as sinon from 'sinon';

import {
formatReachability,
summariseReachableVulns,
getReachabilityText,
} from '../src/cli/commands/test/formatters/format-reachability';
import { REACHABILITY } from '../src/lib/snyk-test/legacy';
import { AnnotatedIssue, REACHABILITY } from '../src/lib/snyk-test/legacy';
import {
serializeCallGraphWithMetrics,
validatePayload,
Expand Down Expand Up @@ -35,6 +36,75 @@ test('reachable text', (t) => {
t.end();
});

test('formatReachabilitySummaryText', (t) => {
const noReachabilityMetadata = {} as AnnotatedIssue;
const noInfoVuln = { reachability: REACHABILITY.NO_INFO } as AnnotatedIssue;
const unreachableVuln = {
reachability: REACHABILITY.UNREACHABLE,
} as AnnotatedIssue;
const reachableByPackageVuln = {
reachability: REACHABILITY.PACKAGE,
} as AnnotatedIssue;
const reachableByFunctionVuln = {
reachability: REACHABILITY.FUNCTION,
} as AnnotatedIssue;

t.equal(
summariseReachableVulns([]),
'',
'no vulnerabilities should not display anything',
);

t.equal(
summariseReachableVulns([noReachabilityMetadata]),
'',
'no reachability metadata should not display anything',
);

t.equal(
summariseReachableVulns([noInfoVuln]),
'',
'no info should not display anything',
);

t.equal(
summariseReachableVulns([unreachableVuln]),
'',
'unreachable is not implemented yet, should not display anything',
);

t.equal(
summariseReachableVulns([reachableByPackageVuln]),
'',
'package is not implemented yet, should not display anything',
);

t.equal(
summariseReachableVulns([reachableByFunctionVuln]),
'In addition, found 1 vulnerability with a reachable path.',
'one reachable function summary text',
);

t.equal(
summariseReachableVulns([reachableByFunctionVuln, reachableByFunctionVuln]),
'In addition, found 2 vulnerabilities with a reachable path.',
'two reachable functions summary text',
);

t.equal(
summariseReachableVulns([
reachableByFunctionVuln,
reachableByFunctionVuln,
reachableByPackageVuln,
noInfoVuln,
]),
'In addition, found 2 vulnerabilities with a reachable path.',
'two reachable functions and no info one, should count only the function reachable once',
);

t.end();
});

test('validatePayload - not supported package manager', async (t) => {
const pkgManagers = Object.keys(SUPPORTED_PACKAGE_MANAGER_NAME);
const mavenIndex = pkgManagers.indexOf('maven');
Expand Down

0 comments on commit 3487ca5

Please sign in to comment.