Skip to content

Commit

Permalink
Merge pull request #726 from snyk/feat/add_legal_instruction
Browse files Browse the repository at this point in the history
feat: add legal instructions
  • Loading branch information
lwywoo committed Aug 30, 2019
2 parents 7f2c6f4 + 2b8f433 commit 63927b1
Show file tree
Hide file tree
Showing 9 changed files with 775 additions and 14 deletions.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -56,6 +56,7 @@
"@types/restify": "^4.3.6",
"abbrev": "^1.1.1",
"ansi-escapes": "3.2.0",
"wrap-ansi": "^5.1.0",
"chalk": "^2.4.2",
"configstore": "^3.1.2",
"debug": "^3.1.0",
Expand Down
6 changes: 5 additions & 1 deletion src/cli/commands/test/formatters/legacy-format-issue.ts
@@ -1,5 +1,6 @@
import * as _ from 'lodash';
import chalk from 'chalk';
import * as wrap from 'wrap-ansi';
import * as config from '../../../../lib/config';
import {Options, TestOptions} from '../../../../lib/types';
import {isLocalFolder} from '../../../../lib/detect';
Expand Down Expand Up @@ -42,6 +43,8 @@ export function formatIssues(vuln: GroupedVuln, options: Options & TestOptions)
: '',
fixedIn: options.docker ? createFixedInText(vuln) : '',
dockerfilePackage: options.docker ? dockerfileInstructionText(vuln) : '',
legalInstructions: vuln.legalInstructions ? '\n Legal instructions:\n '
+ wrap(vuln.legalInstructions, 100).split('\n').join('\n ') : '',
};

return (
Expand All @@ -54,7 +57,8 @@ export function formatIssues(vuln: GroupedVuln, options: Options & TestOptions)
vulnOutput.remediationInfo +
vulnOutput.dockerfilePackage +
vulnOutput.fixedIn +
vulnOutput.extraInfo
vulnOutput.extraInfo +
vulnOutput.legalInstructions
);
}

Expand Down
35 changes: 22 additions & 13 deletions src/cli/commands/test/formatters/remediation-based-format-issues.ts
@@ -1,5 +1,6 @@
import * as _ from 'lodash';
import chalk from 'chalk';
import * as wrap from 'wrap-ansi';
import * as config from '../../../../lib/config';
import { TestOptions } from '../../../../lib/types';
import { RemediationResult, PatchRemediation,
Expand All @@ -13,13 +14,14 @@ interface BasicVulnInfo {
name: string;
version: string;
fixedIn: string[];
legalInstructions?: string;
}

export function formatIssuesWithRemediation(
vulns: GroupedVuln[],
remediationInfo: RemediationResult,
options: TestOptions,
): string[] {
): string[] {

const basicVulnInfo: {
[name: string]: BasicVulnInfo,
Expand All @@ -33,6 +35,7 @@ export function formatIssuesWithRemediation(
name: vuln.name,
version: vuln.version,
fixedIn: vuln.fixedIn,
legalInstructions: vuln.legalInstructions,
};
}
const results = [chalk.bold.white('Remediation advice')];
Expand Down Expand Up @@ -68,7 +71,7 @@ function constructPatchesText(
basicVulnInfo: {
[name: string]: BasicVulnInfo;
},
): string[] {
): string[] {

if (!(Object.keys(patches).length > 0)) {
return [];
Expand All @@ -85,7 +88,8 @@ function constructPatchesText(
basicVulnInfo[id].title,
basicVulnInfo[id].severity,
basicVulnInfo[id].isNew,
`${basicVulnInfo[id].name}@${basicVulnInfo[id].version}`);
`${basicVulnInfo[id].name}@${basicVulnInfo[id].version}`,
basicVulnInfo[id].legalInstructions);
patchedTextArray.push(patchedText + thisPatchFixes);
}

Expand All @@ -97,7 +101,7 @@ function constructUpgradesText(
basicVulnInfo: {
[name: string]: BasicVulnInfo;
},
): string[] {
): string[] {

if (!(Object.keys(upgrades).length > 0)) {
return [];
Expand All @@ -108,15 +112,16 @@ function constructUpgradesText(
const upgradeDepTo = _.get(upgrades, [upgrade, 'upgradeTo']);
const vulnIds = _.get(upgrades, [upgrade, 'vulns']);
const upgradeText =
`\n Upgrade ${chalk.bold.whiteBright(upgrade)} to ${chalk.bold.whiteBright(upgradeDepTo)} to fix\n`;
`\n Upgrade ${chalk.bold.whiteBright(upgrade)} to ${chalk.bold.whiteBright(upgradeDepTo)} to fix\n`;
const thisUpgradeFixes = vulnIds
.sort((a, b) => getSeverityValue(basicVulnInfo[a].severity) - getSeverityValue(basicVulnInfo[b].severity))
.map((id) => formatIssue(
id,
basicVulnInfo[id].title,
basicVulnInfo[id].severity,
basicVulnInfo[id].isNew,
`${basicVulnInfo[id].name}@${basicVulnInfo[id].version}`))
id,
basicVulnInfo[id].title,
basicVulnInfo[id].severity,
basicVulnInfo[id].isNew,
`${basicVulnInfo[id].name}@${basicVulnInfo[id].version}`,
basicVulnInfo[id].legalInstructions))
.join('\n');
upgradeTextArray.push(upgradeText + thisUpgradeFixes);
}
Expand All @@ -140,8 +145,8 @@ function constructUnfixableText(unresolved: IssueData[]) {
issue.id,
issue.title,
issue.severity,
issue.isNew) + `${extraInfo}`,
);
issue.isNew,
issue.legalInstructions) + `${extraInfo}`);
}

return unfixableIssuesTextArray;
Expand All @@ -152,6 +157,7 @@ function formatIssue(
title: string,
severity: SEVERITY,
isNew: boolean,
legalInstructions?: string,
vulnerableModule?: string): string {
const severitiesColourMapping = {
low: {
Expand All @@ -172,10 +178,13 @@ function formatIssue(
};
const newBadge = isNew ? ' (new)' : '';
const name = vulnerableModule ? ` in ${chalk.bold(vulnerableModule)}` : '';
const wrapLegalText = wrap(`${legalInstructions}`, 100);
const formatLegalText = wrapLegalText.split('\n').join('\n ');

return severitiesColourMapping[severity].colorFunc(
` ✗ ${chalk.bold(title)}${newBadge} [${titleCaseText(severity)} Severity]`,
) + `[${config.ROOT}/vuln/${id}]` + name;
) + `[${config.ROOT}/vuln/${id}]` + name
+ (legalInstructions ? `${chalk.bold('\n Legal instructions')}:\n ${formatLegalText}` : '');
}

function titleCaseText(text) {
Expand Down
1 change: 1 addition & 0 deletions src/cli/commands/test/index.ts
Expand Up @@ -475,6 +475,7 @@ function groupVulnerabilities(vulns): GroupedVuln[] {
map[curr.id].dockerfileInstruction = curr.dockerfileInstruction;
map[curr.id].dockerBaseImage = curr.dockerBaseImage;
map[curr.id].nearestFixedInVersion = curr.nearestFixedInVersion;
map[curr.id].legalInstructions = curr.legalInstructions;
}

map[curr.id].list.push(curr);
Expand Down
2 changes: 2 additions & 0 deletions src/lib/snyk-test/legacy.ts
Expand Up @@ -49,6 +49,7 @@ export interface GroupedVuln {
dockerfileInstruction: string;
dockerBaseImage: string;
nearestFixedInVersion: string;
legalInstructions?: string;
}

export interface IssueData {
Expand All @@ -70,6 +71,7 @@ export interface IssueData {
title: string;
severity: SEVERITY;
fixedIn: string[];
legalInstructions?: string;
}

interface AnnotatedIssue extends IssueData {
Expand Down
35 changes: 35 additions & 0 deletions test/acceptance/display-test-results.test.ts
Expand Up @@ -30,6 +30,41 @@ test('`test ruby-app` remediation displayed', async (t) => {
t.end();
});


test('`test ruby-app` legal instructions displayed', async (t) => {
chdirWorkspaces();
const stubbedResponse = JSON.parse(
fs.readFileSync(__dirname + '/workspaces/ruby-app/test-graph-response-with-legal-instruction.json', 'utf8'),
);
const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse);
try {
await snykTest('ruby-app');
} catch (error) {
const res = error.message;
t.match(res, 'Legal instructions');
}

snykTestStub.restore();
t.end();
});

test('`test pip-app-license-issue` legal instructions displayed (legacy formatter)', async (t) => {
chdirWorkspaces();
const stubbedResponse = JSON.parse(
fs.readFileSync(__dirname + '/workspaces/pip-app-license-issue/test-pip-stub-with-legal-instructions.json', 'utf8'),
);
const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse);
try {
await snykTest('pip-app-license-issue');
} catch (error) {
const res = error.message;
t.match(res, 'Legal instructions');
}

snykTestStub.restore();
t.end();
});

function chdirWorkspaces(subdir: string = '') {
process.chdir(__dirname + '/workspaces' + (subdir ? '/' + subdir : ''));
}
@@ -0,0 +1,3 @@
# The following library requires Python >= 3.4.2
# For more see: https://pypi.python.org/pypi?:action=browse&show=all&c=595
aiohttp==2.2.2
@@ -0,0 +1,51 @@
{
"vulnerabilities": [
{
"license": "LGPL-3.0",
"semver": {
"vulnerable": [
"[0,)"
]
},
"id": "snyk:lic:pip:chardet:LGPL-3.0",
"type": "license",
"legalInstructions": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
"packageManager": "pip",
"language": "python",
"packageName": "chardet",
"title": "LGPL-3.0 license",
"description": "LGPL-3.0 license",
"publicationTime": "2019-04-11T10:30:09.818Z",
"creationTime": "2019-04-11T10:30:09.818Z",
"patches": [],
"licenseTemplateUrl": "https://raw.githubusercontent.com/spdx/license-list/master/LGPL-3.0.txt",
"severity": "medium",
"from": [
"python-pip3-app-no-policy@0.0.0",
"aiohttp@2.2.2",
"chardet@3.0.4"
],
"upgradePath": [],
"isUpgradable": false,
"isPatchable": false,
"name": "chardet",
"version": "3.0.4"
}
],
"ok": false,
"dependencyCount": 6,
"org": "lwywoo",
"policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.13.5\nignore: {}\npatch: {}\n",
"isPrivate": true,
"licensesPolicy": null,
"packageManager": "pip",
"ignoreSettings": null,
"summary": "1 vulnerable dependency path",
"filesystemPolicy": false,
"filtered": {
"ignore": [],
"patch": []
},
"uniqueCount": 1,
"path": "/Users/snyk/laura/fixtures/python-pip3-app-no-policy"
}

0 comments on commit 63927b1

Please sign in to comment.