"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 }