"Fossies" - the Fresh Open Source Software Archive 
Member "cli-1.1260.0/src/lib/formatters/legacy-format-issue.ts" (4 Dec 2023, 7606 Bytes) of package /linux/misc/snyk-cli-1.1260.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TypeScript source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 const uniq = require('lodash.uniq');
2 import chalk from 'chalk';
3
4 import { Options, TestOptions, ShowVulnPaths } from '../../lib/types';
5 import { isLocalFolder } from '../../lib/detect';
6 import { parsePackageString as snykModule } from 'snyk-module';
7 import {
8 PINNING_SUPPORTED_PACKAGE_MANAGERS,
9 SupportedPackageManagers,
10 } from '../../lib/package-managers';
11 import {
12 GroupedVuln,
13 AnnotatedIssue,
14 DockerIssue,
15 SEVERITY,
16 } from '../../lib/snyk-test/legacy';
17 import { formatLegalInstructions } from './legal-license-instructions';
18 import { colorTextBySeverity } from '../../lib/snyk-test/common';
19 import { PATH_SEPARATOR } from '../constants';
20 import { getVulnerabilityUrl } from './get-vuln-url';
21
22 export function formatIssues(
23 vuln: GroupedVuln,
24 options: Options & TestOptions,
25 ) {
26 const vulnID = vuln.list[0].id;
27 const packageManager = options.packageManager!;
28 const localPackageTest = isLocalFolder(options.path);
29 const uniquePackages = uniq(
30 vuln.list.map((i) => {
31 if (i.from[1]) {
32 return i.from && i.from[1];
33 }
34 return i.from;
35 }),
36 ).join(', ');
37
38 const vulnOutput = {
39 issueHeading: createSeverityBasedIssueHeading({
40 severity: vuln.metadata.severity,
41 originalSeverity: vuln.originalSeverity,
42 type: vuln.metadata.type,
43 packageName: vuln.metadata.name,
44 isNew: false,
45 }),
46 introducedThrough: ' Introduced through: ' + uniquePackages,
47 description: ' Description: ' + vuln.title,
48 info: ' Info: ' + chalk.underline(getVulnerabilityUrl(vulnID)),
49 fromPaths: createTruncatedVulnsPathsText(vuln.list, options.showVulnPaths),
50 extraInfo: vuln.note ? chalk.bold('\n Note: ' + vuln.note) : '',
51 remediationInfo:
52 vuln.metadata.type !== 'license' && localPackageTest
53 ? createRemediationText(vuln, packageManager)
54 : '',
55 fixedIn: options.docker ? createFixedInText(vuln) : '',
56 dockerfilePackage: options.docker ? dockerfileInstructionText(vuln) : '',
57 legalInstructions: vuln.legalInstructionsArray
58 ? chalk.bold('\n Legal instructions:\n') +
59 ' '.repeat(2) +
60 formatLegalInstructions(vuln.legalInstructionsArray, 2)
61 : '',
62 };
63
64 return (
65 `${vulnOutput.issueHeading}\n` +
66 `${vulnOutput.description}\n` +
67 `${vulnOutput.info}\n` +
68 `${vulnOutput.introducedThrough}\n` +
69 vulnOutput.fromPaths +
70 // Optional - not always there
71 vulnOutput.remediationInfo +
72 vulnOutput.dockerfilePackage +
73 vulnOutput.fixedIn +
74 vulnOutput.extraInfo +
75 vulnOutput.legalInstructions
76 );
77 }
78
79 type CreateSeverityBasedIssueHeading = {
80 severity: SEVERITY;
81 originalSeverity?: SEVERITY;
82 type: string;
83 packageName: string;
84 isNew: boolean;
85 };
86
87 function createSeverityBasedIssueHeading({
88 severity,
89 originalSeverity,
90 type,
91 packageName,
92 isNew,
93 }: CreateSeverityBasedIssueHeading) {
94 // Example: ✗ Medium severity vulnerability found in xmldom
95 const vulnTypeText = type === 'license' ? 'issue' : 'vulnerability';
96
97 let originalSeverityStr = '';
98 if (originalSeverity && originalSeverity !== severity) {
99 originalSeverityStr = ` (originally ${titleCaseText(originalSeverity)})`;
100 }
101
102 return (
103 colorTextBySeverity(
104 severity,
105 '✗ ' +
106 titleCaseText(severity) +
107 ` severity${originalSeverityStr} ` +
108 vulnTypeText +
109 ' found in ' +
110 chalk.underline(packageName),
111 ) + chalk.bold.magenta(isNew ? ' (new)' : '')
112 );
113 }
114
115 export function titleCaseText(text) {
116 return text[0].toUpperCase() + text.slice(1);
117 }
118
119 function dockerfileInstructionText(vuln) {
120 if (vuln.dockerfileInstruction) {
121 JSON.stringify(vuln.dockerfileInstruction);
122 return `\n Image layer: '${vuln.dockerfileInstruction}'`;
123 }
124
125 if (vuln.dockerBaseImage) {
126 return `\n Image layer: Introduced by your base image (${vuln.dockerBaseImage})`;
127 }
128
129 return '';
130 }
131 function createTruncatedVulnsPathsText(
132 vulnList: AnnotatedIssue[],
133 show: ShowVulnPaths,
134 ) {
135 if (show === 'none') {
136 return '';
137 }
138 const numberOfPathsToDisplay = show === 'all' ? 1000 : 3;
139 const fromPathsArray = vulnList.map((i) => i.from);
140
141 const formatedFromPathsArray = fromPathsArray.map((i) => {
142 const fromWithoutBaseProject = i.slice(1);
143 // If more than one From path
144 if (fromWithoutBaseProject.length) {
145 return i.slice(1).join(PATH_SEPARATOR);
146 }
147 // Else issue is in the core package
148 return i;
149 });
150
151 const notShownPathsNumber = fromPathsArray.length - numberOfPathsToDisplay;
152 const shouldTruncatePaths = fromPathsArray.length > numberOfPathsToDisplay;
153 const truncatedText = `\n and ${notShownPathsNumber} more...`;
154 const formattedPathsText = formatedFromPathsArray
155 .slice(0, numberOfPathsToDisplay)
156 .join('\n From: ');
157
158 if (fromPathsArray.length > 0) {
159 return (
160 ' From: ' +
161 formattedPathsText +
162 (shouldTruncatePaths ? truncatedText : '')
163 );
164 }
165 }
166
167 function createFixedInText(vuln: GroupedVuln): string {
168 if ((vuln as DockerIssue).nearestFixedInVersion) {
169 return chalk.bold(
170 '\n Fixed in: ' + (vuln as DockerIssue).nearestFixedInVersion,
171 );
172 } else if (vuln.fixedIn && vuln.fixedIn.length > 0) {
173 return chalk.bold('\n Fixed in: ' + vuln.fixedIn.join(', '));
174 }
175
176 return '';
177 }
178
179 function createRemediationText(
180 vuln: GroupedVuln,
181 packageManager: SupportedPackageManagers,
182 ): string {
183 if (
184 vuln.fixedIn &&
185 PINNING_SUPPORTED_PACKAGE_MANAGERS.includes(packageManager)
186 ) {
187 const toVersion = vuln.fixedIn.join(' or ');
188 const transitive = vuln.list.every((i) => i.from.length > 2);
189 const fromVersionArray = vuln.list.map((v) => v.from[1]);
190 const fromVersion = fromVersionArray[0];
191 if (transitive) {
192 return chalk.bold(
193 `\n Remediation:\n Pin the transitive dependency ${vuln.name} to version ${toVersion}`,
194 );
195 } else {
196 return chalk.bold(
197 `\n Remediation:\n Upgrade direct dependency ${fromVersion} to ${vuln.name}@${toVersion}`,
198 );
199 }
200 }
201
202 if (vuln.isFixable === true) {
203 const upgradePathsArray = uniq(
204 vuln.list.map((v) => {
205 const shouldUpgradeItself = !!v.upgradePath[0];
206 const shouldUpgradeDirectDep = !!v.upgradePath[1];
207
208 if (shouldUpgradeItself) {
209 // If we are testing a library/package like express
210 // Then we can suggest they get the latest version
211 // Example command: snyk test express@3
212 const selfUpgradeInfo =
213 v.upgradePath.length > 0
214 ? ` (triggers upgrades to ${v.upgradePath.join(PATH_SEPARATOR)})`
215 : '';
216 const testedPackageName = snykModule(v.upgradePath[0] as string);
217 return (
218 `You've tested an outdated version of ${testedPackageName[0]}.` +
219 +` Upgrade to ${v.upgradePath[0]}${selfUpgradeInfo}`
220 );
221 }
222 if (shouldUpgradeDirectDep) {
223 const formattedUpgradePath = v.upgradePath
224 .slice(1)
225 .join(PATH_SEPARATOR);
226 const upgradeTextInfo = v.upgradePath.length
227 ? ` (triggers upgrades to ${formattedUpgradePath})`
228 : '';
229
230 return `Upgrade direct dependency ${v.from[1]} to ${v.upgradePath[1]}${upgradeTextInfo}`;
231 }
232
233 return 'Some paths have no direct dependency upgrade that can address this issue.';
234 }),
235 );
236 return chalk.bold(
237 `\n Remediation:\n ${upgradePathsArray.join('\n ')}`,
238 );
239 }
240
241 if (vuln.fixedIn && vuln.fixedIn.length > 0) {
242 return createFixedInText(vuln);
243 }
244
245 return '';
246 }