From 93c84bd346dc3752be40939bfa45117c0e8513a4 Mon Sep 17 00:00:00 2001 From: David Agrest Date: Wed, 16 Nov 2022 10:33:39 +0200 Subject: [PATCH] feat: os output update - add issue summary --- .../remediation-based-format-issues.ts | 298 ++++++++++++------ .../formatters/test/format-test-results.ts | 82 ++++- src/lib/formatters/types.ts | 13 + .../cli-output-actionable-remediation.txt | 26 +- ...mediation-based-format-issues.spec.ts.snap | 112 ++++--- .../remediation-based-format-issues.spec.ts | 8 +- .../__snapshots__/display-result.spec.ts.snap | 130 ++++---- .../formatters/test/display-result.spec.ts | 17 +- test/tap/display-test-results.test.ts | 7 +- 9 files changed, 446 insertions(+), 247 deletions(-) diff --git a/src/lib/formatters/remediation-based-format-issues.ts b/src/lib/formatters/remediation-based-format-issues.ts index 73c6fe55a3..14efe9f43d 100644 --- a/src/lib/formatters/remediation-based-format-issues.ts +++ b/src/lib/formatters/remediation-based-format-issues.ts @@ -15,16 +15,26 @@ import { } from '../../lib/snyk-test/legacy'; import { colorTextBySeverity } from '../../lib/snyk-test/common'; import { formatLegalInstructions } from './legal-license-instructions'; -import { BasicVulnInfo, UpgradesByAffectedPackage } from './types'; +import { + BasicVulnInfo, + FormattedIssuesWithRemediation, + UpgradesByAffectedPackage, +} from './types'; import { PATH_SEPARATOR } from '../constants'; import { getSeverityValue } from './get-severity-value'; import { getVulnerabilityUrl } from './get-vuln-url'; +type ConstructIssuesTextOutput = { + textArray: string[]; + countTotal: number; + countBySeverity?: { [severity in SEVERITY]: number }; +}; + export function formatIssuesWithRemediation( vulns: GroupedVuln[], remediationInfo: RemediationChanges, options: TestOptions, -): string[] { +): FormattedIssuesWithRemediation { const basicVulnInfo: { [name: string]: BasicVulnInfo; } = {}; @@ -54,9 +64,19 @@ export function formatIssuesWithRemediation( } } - const results = ['']; + const results: FormattedIssuesWithRemediation = { + outputTextArray: [], + counts: { + noUpgradeOrPatchCount: 0, + licenseTotal: 0, + fixableTotal: 0, + licenseBySeverity: { low: 0, medium: 0, high: 0, critical: 0 }, + fixableBySeverity: { low: 0, medium: 0, high: 0, critical: 0 }, + }, + }; + + let upgradeIssues = {} as ConstructIssuesTextOutput; - let upgradeTextArray: string[]; if (remediationInfo.pin && Object.keys(remediationInfo.pin).length) { const upgradesByAffected: UpgradesByAffectedPackage = {}; for (const topLevelPkg of Object.keys(remediationInfo.upgrade)) { @@ -71,7 +91,7 @@ export function formatIssuesWithRemediation( }); } } - upgradeTextArray = constructPinText( + upgradeIssues = constructPinText( remediationInfo.pin, upgradesByAffected, basicVulnInfo, @@ -85,44 +105,62 @@ export function formatIssuesWithRemediation( (issue) => !allVulnIds.has(issue.id), ); } else { - upgradeTextArray = constructUpgradesText( + upgradeIssues = constructUpgradesText( remediationInfo.upgrade, basicVulnInfo, options, ); } - const patchedTextArray = constructPatchesText( + let patchedIssues = {} as ConstructIssuesTextOutput; + patchedIssues = constructPatchesText( remediationInfo.patch, basicVulnInfo, options, ); - const unfixableIssuesTextArray = constructUnfixableText( + let unfixableIssues = {} as ConstructIssuesTextOutput; + unfixableIssues = constructUnfixableText( remediationInfo.unresolved, basicVulnInfo, options, ); - const licenseIssuesTextArray = constructLicenseText( - basicLicenseInfo, - options, - ); + let licenseIssues = {} as ConstructIssuesTextOutput; + licenseIssues = constructLicenseText(basicLicenseInfo, options); - if (unfixableIssuesTextArray.length > 0) { - results.push(unfixableIssuesTextArray.join('\n')); + if (unfixableIssues.textArray?.length > 0) { + results.outputTextArray.push(unfixableIssues.textArray.join('\n')); + results.counts.noUpgradeOrPatchCount += unfixableIssues.countTotal; } - if (licenseIssuesTextArray.length > 0) { - results.push(licenseIssuesTextArray.join('\n')); + if (licenseIssues.textArray?.length > 0) { + results.outputTextArray.push(licenseIssues.textArray.join('\n')); + results.counts.licenseTotal += licenseIssues.countTotal; + if (licenseIssues.countBySeverity) { + results.counts.licenseBySeverity = licenseIssues.countBySeverity; + } } - if (patchedTextArray.length > 0) { - results.push(patchedTextArray.join('\n')); + if (patchedIssues.textArray?.length > 0) { + results.outputTextArray.push(patchedIssues.textArray.join('\n')); + results.counts.fixableTotal += patchedIssues.countTotal; + if (patchedIssues.countBySeverity) { + Object.keys(patchedIssues.countBySeverity).forEach((severity) => { + if (patchedIssues.countBySeverity) { + results.counts.fixableBySeverity[severity] += + patchedIssues.countBySeverity[severity]; + } + }); + } } - if (upgradeTextArray.length > 0) { - results.push(upgradeTextArray.join('\n')); + if (upgradeIssues.textArray?.length > 0) { + results.outputTextArray.push(upgradeIssues.textArray.join('\n')); + results.counts.fixableTotal += upgradeIssues.countTotal; + if (upgradeIssues.countBySeverity) { + results.counts.fixableBySeverity = upgradeIssues.countBySeverity; + } } return results; @@ -133,13 +171,16 @@ function constructLicenseText( [name: string]: BasicVulnInfo; }, testOptions: TestOptions, -): string[] { +): ConstructIssuesTextOutput { if (!(Object.keys(basicLicenseInfo).length > 0)) { - return []; + return {} as ConstructIssuesTextOutput; } - const licenseTextArray: string[] = []; - let issuesCount = 0; + const licenseIssues: ConstructIssuesTextOutput = { + textArray: [], + countTotal: 0, + countBySeverity: { low: 0, medium: 0, high: 0, critical: 0 }, + }; for (const id of Object.keys(basicLicenseInfo)) { const licenseText = formatIssue( @@ -154,17 +195,26 @@ function constructLicenseText( undefined, // We can never override license rules, so no originalSeverity here basicLicenseInfo[id].legalInstructions, ); - licenseTextArray.push(licenseText); - issuesCount += 1; + licenseIssues.textArray.push(licenseText); + licenseIssues.countTotal += 1; + if (licenseIssues.countBySeverity) { + licenseIssues.countBySeverity[basicLicenseInfo[id].severity] += 1; + } } - licenseTextArray.unshift( - chalk.bold.green( - `\nLicense issues (${issuesCount} ${ - issuesCount > 1 ? 'issues' : 'issue' + + licenseIssues.textArray.unshift( + chalk.bold( + `\nLicense issues (${licenseIssues.countTotal} ${ + licenseIssues.countTotal > 1 ? 'issues' : 'issue' }):`, ), ); - return licenseTextArray; + + return { + textArray: licenseIssues.textArray, + countTotal: licenseIssues.countTotal, + countBySeverity: licenseIssues.countBySeverity, + }; } function constructPatchesText( @@ -175,12 +225,15 @@ function constructPatchesText( [name: string]: BasicVulnInfo; }, testOptions: TestOptions, -): string[] { +): ConstructIssuesTextOutput { if (!(Object.keys(patches).length > 0)) { - return []; + return {} as ConstructIssuesTextOutput; } - const patchedTextArray: string[] = []; - let patchedCount = 0; + const patchedIssues: ConstructIssuesTextOutput = { + textArray: [], + countTotal: 0, + countBySeverity: { low: 0, medium: 0, high: 0, critical: 0 }, + }; for (const id of Object.keys(patches)) { if (!basicVulnInfo[id]) { continue; @@ -205,26 +258,40 @@ function constructPatchesText( basicVulnInfo[id].note, basicVulnInfo[id].originalSeverity, ); - patchedTextArray.push(patchedText + thisPatchFixes); - patchedCount += 1; + patchedIssues.textArray.push(patchedText + thisPatchFixes); + patchedIssues.countTotal += 1; + if (patchedIssues.countBySeverity) { + patchedIssues.countBySeverity[basicVulnInfo[id].severity] += 1; + } } - patchedTextArray.unshift( - chalk.bold.green( - `\nPatchable issues (${patchedCount} ${ - patchedCount > 1 ? 'issues' : 'issue' + + patchedIssues.textArray.unshift( + chalk.bold( + `\nPatchable issues (${patchedIssues.countTotal} ${ + patchedIssues.countTotal > 1 ? 'issues' : 'issue' }):`, ), ); - return patchedTextArray; + return { + textArray: patchedIssues.textArray, + countTotal: patchedIssues.countTotal, + countBySeverity: patchedIssues.countBySeverity, + }; } function thisUpgradeFixes( vulnIds: string[], basicVulnInfo: Record, testOptions: TestOptions, -) { - return vulnIds +): ConstructIssuesTextOutput { + const fixedIssues: ConstructIssuesTextOutput = { + textArray: [], + countTotal: 0, + countBySeverity: { low: 0, medium: 0, high: 0, critical: 0 }, + }; + + fixedIssues.textArray = vulnIds .filter((id) => basicVulnInfo[id]) // basicVulnInfo only contains issues with the specified severity levels .sort( (a, b) => @@ -246,19 +313,27 @@ function thisUpgradeFixes( [], ), ); + fixedIssues.countTotal = fixedIssues.textArray.length; + + Object.values(SEVERITY).forEach((severity) => { + if (fixedIssues.countBySeverity) { + fixedIssues.countBySeverity[severity] += vulnIds + .filter((id) => basicVulnInfo[id]) + .filter((id) => basicVulnInfo[id].type !== 'license') + .filter((id) => basicVulnInfo[id].severity === severity).length; + } + }); + return fixedIssues; } function processUpgrades( - sink: { - textArray: string[]; - count: number; - }, + sink: ConstructIssuesTextOutput, upgradesByDep: DependencyUpdates | DependencyPins, deps: string[], basicVulnInfo: Record, testOptions: TestOptions, ) { - sink.count = 0; + sink.countTotal = 0; for (const dep of deps) { const data = upgradesByDep[dep]; const upgradeDepTo = data.upgradeTo; @@ -267,11 +342,20 @@ function processUpgrades( const fixesArray = thisUpgradeFixes(vulnIds, basicVulnInfo, testOptions); const upgradeText = `\n Upgrade ${chalk.bold.whiteBright( dep, - )} to ${chalk.bold.whiteBright(upgradeDepTo)} to fix ${fixesArray.length} ${ - fixesArray.length > 1 ? 'issues' : 'issue' - }\n`; - sink.textArray.push(upgradeText + fixesArray.join('\n')); - sink.count += fixesArray.length; + )} to ${chalk.bold.whiteBright(upgradeDepTo)} to fix ${ + fixesArray.textArray.length + } ${fixesArray.textArray.length > 1 ? 'issues' : 'issue'}\n`; + sink.textArray.push(upgradeText + fixesArray.textArray.join('\n')); + sink.countTotal += fixesArray.countTotal; + if (fixesArray.countBySeverity) { + Object.entries(fixesArray.countBySeverity).forEach( + ([severity, count]) => { + if (sink.countBySeverity) { + sink.countBySeverity[severity] += count; + } + }, + ); + } } } @@ -281,14 +365,15 @@ function constructUpgradesText( [name: string]: BasicVulnInfo; }, testOptions: TestOptions, -): string[] { +): ConstructIssuesTextOutput { if (!(Object.keys(upgrades).length > 0)) { - return []; + return {} as ConstructIssuesTextOutput; } - const upgradeIssues: { textArray: string[]; count: number } = { + const upgradeIssues: ConstructIssuesTextOutput = { textArray: [], - count: 0, + countTotal: 0, + countBySeverity: { low: 0, medium: 0, high: 0, critical: 0 }, }; processUpgrades( @@ -299,14 +384,18 @@ function constructUpgradesText( testOptions, ); upgradeIssues.textArray.unshift( - chalk.bold.green( - `\nIssues to fix by upgrading (${upgradeIssues.count} ${ - upgradeIssues.count > 1 ? 'issues' : 'issue' + chalk.bold( + `\nIssues to fix by upgrading (${upgradeIssues.countTotal} ${ + upgradeIssues.countTotal > 1 ? 'issues' : 'issue' }):`, ), ); - return upgradeIssues.textArray; + return { + textArray: upgradeIssues.textArray, + countTotal: upgradeIssues.countTotal, + countBySeverity: upgradeIssues.countBySeverity, + }; } function constructPinText( @@ -314,16 +403,17 @@ function constructPinText( upgradesByAffected: UpgradesByAffectedPackage, // classical "remediation via top-level dep" upgrades basicVulnInfo: Record, testOptions: TestOptions, -): string[] { +): ConstructIssuesTextOutput { if (!Object.keys(pins).length) { - return []; + return {} as ConstructIssuesTextOutput; } - // First, direct upgrades - const upgradeIssues: { textArray: string[]; count: number } = { + const upgradeIssues: ConstructIssuesTextOutput = { textArray: [], - count: 0, + countTotal: 0, + countBySeverity: { low: 0, medium: 0, high: 0, critical: 0 }, }; + const upgradeables = Object.keys(pins).filter( (name) => !pins[name].isTransitive, ); @@ -349,11 +439,21 @@ function constructPinText( const upgradeText = `\n Pin ${chalk.bold.whiteBright( pkgName, )} to ${chalk.bold.whiteBright(upgradeDepTo)} to fix ${ - fixesArray.length - } ${fixesArray.length > 1 ? 'issues' : 'issue'}`; - upgradeIssues.textArray.push(upgradeText); + fixesArray.textArray.length + } ${fixesArray.textArray.length > 1 ? 'issues' : 'issue'}`; - upgradeIssues.textArray.push(fixesArray.join('\n')); + upgradeIssues.textArray.push(upgradeText); + upgradeIssues.textArray.push(fixesArray.textArray.join('\n')); + upgradeIssues.countTotal += fixesArray.countTotal; + if (fixesArray.countBySeverity) { + Object.entries(fixesArray.countBySeverity).forEach( + ([severity, count]) => { + if (upgradeIssues.countBySeverity) { + upgradeIssues.countBySeverity[severity] += count; + } + }, + ); + } // Finally, if we have some upgrade paths that fix the same issues, suggest them as well. const topLevelUpgradesAlreadySuggested = new Set(); @@ -373,26 +473,33 @@ function constructPinText( } } } + upgradeIssues.textArray.unshift( - chalk.bold.green( - `\nIssues to fix by upgrading dependencies (${upgradeIssues.count} ${ - upgradeIssues.count > 1 ? 'issues' : 'issue' + chalk.bold( + `\nIssues to fix by upgrading dependencies (${upgradeIssues.countTotal} ${ + upgradeIssues.countTotal > 1 ? 'issues' : 'issue' }):`, ), ); - return upgradeIssues.textArray; + return { + textArray: upgradeIssues.textArray, + countTotal: upgradeIssues.countTotal, + countBySeverity: upgradeIssues.countBySeverity, + }; } function constructUnfixableText( unresolved: IssueData[], basicVulnInfo: Record, testOptions: TestOptions, -) { +): ConstructIssuesTextOutput { if (!(unresolved.length > 0)) { - return []; + return {} as ConstructIssuesTextOutput; } const unfixableIssuesTextArray: string[] = []; + let unfixableCount = 0; + for (const issue of unresolved) { const issueInfo = basicVulnInfo[issue.id]; if (!issueInfo) { @@ -402,9 +509,7 @@ function constructUnfixableText( const extraInfo = issue.fixedIn && issue.fixedIn.length - ? `\n This issue was fixed in versions: ${chalk.bold( - issue.fixedIn.join(', '), - )}` + ? `\n Fixed in: ${chalk.bold(issue.fixedIn.join(', '))}` : '\n No upgrade or patch available'; unfixableIssuesTextArray.push( formatIssue( @@ -420,22 +525,26 @@ function constructUnfixableText( [], ) + `${extraInfo}`, ); + unfixableCount += 1; } unfixableIssuesTextArray.unshift( chalk.bold.white( - `\nIssues with no direct upgrade or patch (${ - unfixableIssuesTextArray.length - } ${unfixableIssuesTextArray.length > 1 ? 'issues' : 'issue'}):`, + `\nIssues with no direct upgrade or patch (${unfixableCount} ${ + unfixableCount > 1 ? 'issues' : 'issue' + }):`, ), ); if (unfixableIssuesTextArray.length === 1) { // seems we still only have // the initial section title, so nothing to return - return []; + return {} as ConstructIssuesTextOutput; } - return unfixableIssuesTextArray; + return { + textArray: unfixableIssuesTextArray, + countTotal: unfixableCount, + }; } export function printPath(path: string[], slice = 1) { @@ -455,7 +564,9 @@ export function formatIssue( legalInstructions?: LegalInstruction[], ): string { const newBadge = isNew ? ' (new)' : ''; - const name = vulnerableModule ? ` in ${chalk.bold(vulnerableModule)}` : ''; + const introducedThrough = vulnerableModule + ? `\n Introduced through: ${chalk.bold(vulnerableModule)}` + : ''; let legalLicenseInstructionsText; if (legalInstructions) { legalLicenseInstructionsText = formatLegalInstructions(legalInstructions); @@ -472,17 +583,17 @@ export function formatIssue( const pathStr = printPath(paths[0]); introducedBy = paths.length === 1 - ? `\n introduced by ${pathStr}` - : `\n introduced by ${pathStr} and ${chalk.cyanBright( + ? `\n Introduced by: ${pathStr}` + : `\n Introduced by: ${pathStr} and ${chalk.cyanBright( '' + (paths.length - 1), )} other path(s)`; } else if (testOptions.showVulnPaths === 'all' && paths) { introducedBy = - '\n introduced by:' + + '\n Introduced by:' + paths .slice(0, 1000) - .map((p) => '\n ' + printPath(p)) - .join(''); + .map((p) => ' ' + printPath(p)) + .join(' >'); if (paths.length > 1000) { introducedBy += `\n and ${chalk.cyanBright( '' + (paths.length - 1), @@ -503,9 +614,8 @@ export function formatIssue( severity, )}${originalSeverityStr}] ${chalk.bold(title)}${newBadge}`, ) + - '\n ' + - `[${getVulnerabilityUrl(id)}]` + - name + + `\n Info: ${getVulnerabilityUrl(id)}` + + introducedThrough + introducedBy + (legalLicenseInstructionsText ? `${chalk.bold( diff --git a/src/lib/formatters/test/format-test-results.ts b/src/lib/formatters/test/format-test-results.ts index d450c15c65..de8fb77fb9 100644 --- a/src/lib/formatters/test/format-test-results.ts +++ b/src/lib/formatters/test/format-test-results.ts @@ -30,6 +30,8 @@ import { facts as dockerFacts, } from 'snyk-docker-plugin/dist'; import { ScanResult } from '../../ecosystems/types'; +import { FormattedIssuesWithRemediation } from '../types'; +import { colorTextBySeverity } from '../../snyk-test/common'; function createJsonResultOutput(jsonResult, options: Options) { const jsonResultClone = cloneDeep(jsonResult); @@ -197,7 +199,17 @@ export function getDisplayedOutput( (vuln) => vuln.metadata.packageManager === 'upstream', ); - let groupedVulnInfoOutput; + let groupedVulnInfoOutput: FormattedIssuesWithRemediation = { + outputTextArray: [], + counts: { + noUpgradeOrPatchCount: 0, + licenseTotal: 0, + fixableTotal: 0, + licenseBySeverity: { low: 0, medium: 0, high: 0, critical: 0 }, + fixableBySeverity: { low: 0, medium: 0, high: 0, critical: 0 }, + }, + }; + if (res.remediation) { analytics.add('actionableRemediation', true); groupedVulnInfoOutput = formatIssuesWithRemediation( @@ -207,8 +219,8 @@ export function getDisplayedOutput( ); } else { analytics.add('actionableRemediation', false); - groupedVulnInfoOutput = filteredSortedGroupedVulns.map((vuln) => - formatIssues(vuln, options), + groupedVulnInfoOutput.outputTextArray = filteredSortedGroupedVulns.map( + (vuln) => formatIssues(vuln, options), ); } @@ -221,15 +233,73 @@ export function getDisplayedOutput( ) : []; + const licenseBySeverityText = `${Object.keys( + groupedVulnInfoOutput.counts.licenseBySeverity, + ) + .reverse() + .filter( + (severity) => + groupedVulnInfoOutput.counts.licenseBySeverity[severity] > 0, + ) + .map((severity) => + colorTextBySeverity( + severity, + chalk.bold( + `${ + groupedVulnInfoOutput.counts.licenseBySeverity[severity] + } ${severity.charAt(0).toUpperCase() + severity.slice(1)}`, + ), + ), + ) + .join(', ')}`; + const fixableBySeverityText = `${Object.keys( + groupedVulnInfoOutput.counts.fixableBySeverity, + ) + .reverse() + .filter( + (severity) => + groupedVulnInfoOutput.counts.fixableBySeverity[severity] > 0, + ) + .map((severity) => + colorTextBySeverity( + severity, + chalk.bold( + `${ + groupedVulnInfoOutput.counts.fixableBySeverity[severity] + } ${severity.charAt(0).toUpperCase() + severity.slice(1)}`, + ), + ), + ) + .join(', ')}`; + + const testSummary = `${ + !options.docker + ? `${chalk.bold('\n\nTest summary:')}\n${ + groupedVulnInfoOutput.counts.noUpgradeOrPatchCount + ? `\n ${groupedVulnInfoOutput.counts.noUpgradeOrPatchCount} issues with no upgrade or patch` + : '' + }${ + groupedVulnInfoOutput.counts.licenseTotal + ? `\n ${groupedVulnInfoOutput.counts.licenseTotal} license issues: ` + : '' + }${licenseBySeverityText}${ + groupedVulnInfoOutput.counts.fixableTotal + ? `\n ${groupedVulnInfoOutput.counts.fixableTotal} fixable issues: ` + : '' + }${fixableBySeverityText}` + : '' + }`; + let body = - groupedVulnInfoOutput.join('\n\n') + + groupedVulnInfoOutput.outputTextArray.join('\n\n') + '\n\n' + groupedDockerBinariesVulnInfoOutput.join('\n\n') + '\n\n' + - meta; + meta + + `${res.remediation ? `${testSummary}` : ''}`; if (res.remediation) { - body = summary + body + fixAdvice; + body = summary + '\n\n' + body + fixAdvice; } else { body = body + '\n\n' + summary + fixAdvice; } diff --git a/src/lib/formatters/types.ts b/src/lib/formatters/types.ts index 0ec9399854..be887cb7c7 100644 --- a/src/lib/formatters/types.ts +++ b/src/lib/formatters/types.ts @@ -22,3 +22,16 @@ interface TopLevelPackageUpgrade { export interface UpgradesByAffectedPackage { [pkgNameAndVersion: string]: TopLevelPackageUpgrade[]; } + +export type FormattedIssuesCounts = { + noUpgradeOrPatchCount: number; + licenseTotal: number; + fixableTotal: number; + licenseBySeverity: { [severity in SEVERITY]: number }; + fixableBySeverity: { [severity in SEVERITY]: number }; +}; + +export type FormattedIssuesWithRemediation = { + outputTextArray: string[]; + counts: FormattedIssuesCounts; +}; diff --git a/test/acceptance/workspaces/pip-app-transitive-vuln/cli-output-actionable-remediation.txt b/test/acceptance/workspaces/pip-app-transitive-vuln/cli-output-actionable-remediation.txt index b5bc18a55e..56c77ffa54 100644 --- a/test/acceptance/workspaces/pip-app-transitive-vuln/cli-output-actionable-remediation.txt +++ b/test/acceptance/workspaces/pip-app-transitive-vuln/cli-output-actionable-remediation.txt @@ -4,29 +4,33 @@ Testing pip-app-transitive-vuln... Tested 6 dependencies for known vulnerabilities, found 4 vulnerabilities, 4 vulnerable paths. -Issues to fix by upgrading dependencies (2 issues): +Issues to fix by upgrading dependencies (4 issues): Upgrade flask to 1.0 to fix 2 issues ✗ [High] Improper Input Validation - [https://security.snyk.io/vuln/SNYK-PYTHON-FLASK-42185] in flask@0.12.2 - introduced by flask@0.12.2 + Info: https://security.snyk.io/vuln/SNYK-PYTHON-FLASK-42185 + Introduced through: flask@0.12.2 + Introduced by: flask@0.12.2 ✗ [High] Denial of Service (DOS) - [https://security.snyk.io/vuln/SNYK-PYTHON-FLASK-451637] in flask@0.12.2 - introduced by flask@0.12.2 + Info: https://security.snyk.io/vuln/SNYK-PYTHON-FLASK-451637 + Introduced through: flask@0.12.2 + Introduced by: flask@0.12.2 Pin Jinja2 to 2.10.1 to fix 1 issue ✗ [Medium] Sandbox Escape - [https://security.snyk.io/vuln/SNYK-PYTHON-JINJA2-174126] in Jinja2@2.9.6 - introduced by flask@0.12.2 > Jinja2@2.9.6 + Info: https://security.snyk.io/vuln/SNYK-PYTHON-JINJA2-174126 + Introduced through: Jinja2@2.9.6 + Introduced by: flask@0.12.2 > Jinja2@2.9.6 Pin Werkzeug to 0.15.3 to fix 1 issue ✗ [High] Insufficient Randomness - [https://security.snyk.io/vuln/SNYK-PYTHON-WERKZEUG-458931] in Werkzeug@0.12.2 - introduced by flask@0.12.2 > Werkzeug@0.12.2 + Info: https://security.snyk.io/vuln/SNYK-PYTHON-WERKZEUG-458931 + Introduced through: Werkzeug@0.12.2 + Introduced by: flask@0.12.2 > Werkzeug@0.12.2 @@ -37,5 +41,9 @@ Project name: pip-app-transitive-vuln Open source: no Project path: pip-app-transitive-vuln +Test summary: + + 4 fixable issues: 3 High, 1 Medium + Tip: Try `snyk fix` to address these issues.`snyk fix` is a new CLI command in that aims to automatically apply the recommended updates for supported ecosystems. See documentation on how to enable this beta feature: https://docs.snyk.io/snyk-cli/fix-vulnerabilities-from-the-cli/automatic-remediation-with-snyk-fix#enabling-snyk-fix diff --git a/test/jest/unit/lib/formatters/__snapshots__/remediation-based-format-issues.spec.ts.snap b/test/jest/unit/lib/formatters/__snapshots__/remediation-based-format-issues.spec.ts.snap index 1d4272edd1..b490e578e8 100644 --- a/test/jest/unit/lib/formatters/__snapshots__/remediation-based-format-issues.spec.ts.snap +++ b/test/jest/unit/lib/formatters/__snapshots__/remediation-based-format-issues.spec.ts.snap @@ -2,134 +2,130 @@ exports[`with license issues 1`] = ` " - License issues (1 issue): ✗ [High] Unknown license - [URL] in rack-cache@1.1 - introduced by: - rack-cache@1.1 + Info: https://dev.snyk.io/vuln/snyk:lic:rubygems:rack-cache:Unknown + Introduced through: rack-cache@1.1 + Introduced by: rack-cache@1.1 Legal instructions: ○ for LGPL-3.0 license: I am legal license instruction + Issues to fix by upgrading (7 issues): Upgrade rack@1.6.5 to rack@1.6.11 to fix 1 issue ✗ [Medium] Cross-site Scripting (XSS) - [URL] in rack@1.6.5 - introduced by: - rack@1.6.5 - rack-cache@1.1 > rack@1.6.5 - rack-protection@1.5.3 > rack@1.6.5 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACK-72567 + Introduced through: rack@1.6.5 + Introduced by: rack@1.6.5 > rack-cache@1.1 > rack@1.6.5 > rack-protection@1.5.3 > rack@1.6.5 Upgrade rack-cache@1.1 to rack-cache@1.3.0 to fix 2 issues ✗ [Medium] Cross-site Scripting (XSS) - [URL] in rack@1.6.5 - introduced by: - rack@1.6.5 - rack-cache@1.1 > rack@1.6.5 - rack-protection@1.5.3 > rack@1.6.5 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACK-72567 + Introduced through: rack@1.6.5 + Introduced by: rack@1.6.5 > rack-cache@1.1 > rack@1.6.5 > rack-protection@1.5.3 > rack@1.6.5 ✗ [High] HTTP Header Caching Weakness - [URL] in rack-cache@1.1 - introduced by: - rack-cache@1.1 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACKCACHE-20031 + Introduced through: rack-cache@1.1 + Introduced by: rack-cache@1.1 Upgrade rack-protection@1.5.3 to rack-protection@2.0.0 to fix 4 issues ✗ [Low] Side-channel attack - [URL] in rack-protection@1.5.3 - introduced by: - rack-protection@1.5.3 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACKPROTECTION-20394 + Introduced through: rack-protection@1.5.3 + Introduced by: rack-protection@1.5.3 ✗ [Medium] Timing Attack - [URL] in rack-protection@1.5.3 - introduced by: - rack-protection@1.5.3 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACKPROTECTION-20395 + Introduced through: rack-protection@1.5.3 + Introduced by: rack-protection@1.5.3 ✗ [Medium] Directory Traversal - [URL] in rack-protection@1.5.3 - introduced by: - rack-protection@1.5.3 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACKPROTECTION-22019 + Introduced through: rack-protection@1.5.3 + Introduced by: rack-protection@1.5.3 ✗ [Medium] Cross-site Scripting (XSS) - [URL] in rack@1.6.5 - introduced by: - rack@1.6.5 - rack-cache@1.1 > rack@1.6.5 - rack-protection@1.5.3 > rack@1.6.5" + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACK-72567 + Introduced through: rack@1.6.5 + Introduced by: rack@1.6.5 > rack-cache@1.1 > rack@1.6.5 > rack-protection@1.5.3 > rack@1.6.5" `; exports[`with pins & unfixable & showVulnsPaths = all 1`] = ` " - Issues with no direct upgrade or patch (1 issue): ✗ [Low] Directory Traversal - [URL] in django@1.6.1 - introduced by: - django@1.6.1 - This issue was fixed in versions: 2.2.18, 3.0.12, 3.1.6 + Info: https://security.snyk.io/vuln/SNYK-PYTHON-DJANGO-1066259 + Introduced through: django@1.6.1 + Introduced by: django@1.6.1 + Fixed in: 2.2.18, 3.0.12, 3.1.6 + Issues to fix by upgrading dependencies (1 issue): Upgrade django@1.6.1 to django@2.2.18 to fix 1 issue ✗ [Medium] Content Spoofing - [URL] in django@1.6.1 - introduced by: - django@1.6.1" + Info: https://security.snyk.io/vuln/SNYK-PYTHON-DJANGO-72888 + Introduced through: django@1.6.1 + Introduced by: django@1.6.1" `; exports[`with showVulnPaths = some 1`] = ` " - Issues with no direct upgrade or patch (1 issue): ✗ [Low] Directory Traversal - [URL] in django@1.6.1 - introduced by django@1.6.1 - This issue was fixed in versions: 2.2.18, 3.0.12, 3.1.6 + Info: https://security.snyk.io/vuln/SNYK-PYTHON-DJANGO-1066259 + Introduced through: django@1.6.1 + Introduced by: django@1.6.1 + Fixed in: 2.2.18, 3.0.12, 3.1.6 + Issues to fix by upgrading dependencies (1 issue): Upgrade django@1.6.1 to django@2.2.18 to fix 1 issue ✗ [Medium] Content Spoofing - [URL] in django@1.6.1 - introduced by django@1.6.1" + Info: https://security.snyk.io/vuln/SNYK-PYTHON-DJANGO-72888 + Introduced through: django@1.6.1 + Introduced by: django@1.6.1" `; exports[`with upgrades & patches 1`] = ` " - Patchable issues (1 issue): Patch available for node-uuid@1.4.0 ✗ [Low (originally Medium)] Insecure Randomness - [URL] in node-uuid@1.4.0 - introduced by: - node-uuid@1.4.0 + Info: https://security.snyk.io/vuln/npm:node-uuid:20160328 + Introduced through: node-uuid@1.4.0 + Introduced by: node-uuid@1.4.0 + Issues to fix by upgrading (3 issues): Upgrade qs@0.0.6 to qs@6.0.4 to fix 3 issues ✗ [Low (originally High)] Prototype Override Protection Bypass - [URL] in qs@0.0.6 - introduced by: - qs@0.0.6 + Info: https://security.snyk.io/vuln/npm:qs:20170213 + Introduced through: qs@0.0.6 + Introduced by: qs@0.0.6 ✗ [Low (originally High)] Denial of Service (DoS) - [URL] in qs@0.0.6 - introduced by: - qs@0.0.6 + Info: https://security.snyk.io/vuln/npm:qs:20140806 + Introduced through: qs@0.0.6 + Introduced by: qs@0.0.6 ✗ [Low (originally Medium)] Denial of Service (DoS) - [URL] in qs@0.0.6 - introduced by: - qs@0.0.6" + Info: https://security.snyk.io/vuln/npm:qs:20140806-1 + Introduced through: qs@0.0.6 + Introduced by: qs@0.0.6" `; diff --git a/test/jest/unit/lib/formatters/remediation-based-format-issues.spec.ts b/test/jest/unit/lib/formatters/remediation-based-format-issues.spec.ts index 556abff423..79cf2066e8 100644 --- a/test/jest/unit/lib/formatters/remediation-based-format-issues.spec.ts +++ b/test/jest/unit/lib/formatters/remediation-based-format-issues.spec.ts @@ -27,7 +27,7 @@ it('with pins & unfixable & showVulnsPaths = all', () => { { showVulnPaths: 'all' }, ); expect( - stripAnsi(res.join('\n').replace(/\[http.*\]/g, '[URL]')), + stripAnsi(res.outputTextArray.join('\n\n').replace(/\[http.*\]/g, 'URL')), ).toMatchSnapshot(); }); @@ -52,7 +52,7 @@ it('with showVulnPaths = some', () => { { showVulnPaths: 'some' }, ); expect( - stripAnsi(res.join('\n').replace(/\[http.*\]/g, '[URL]')), + stripAnsi(res.outputTextArray.join('\n\n').replace(/\[http.*\]/g, 'URL')), ).toMatchSnapshot(); }); it('with upgrades & patches', () => { @@ -78,7 +78,7 @@ it('with upgrades & patches', () => { { showVulnPaths: 'all' }, ); expect( - stripAnsi(res.join('\n').replace(/\[http.*\]/g, '[URL]')), + stripAnsi(res.outputTextArray.join('\n\n').replace(/\[http.*\]/g, 'URL')), ).toMatchSnapshot(); }); @@ -105,6 +105,6 @@ it('with license issues', () => { { showVulnPaths: 'all' }, ); expect( - stripAnsi(res.join('\n').replace(/\[http.*\]/g, '[URL]')), + stripAnsi(res.outputTextArray.join('\n\n').replace(/\[http.*\]/g, 'URL')), ).toMatchSnapshot(); }); diff --git a/test/jest/unit/lib/formatters/test/__snapshots__/display-result.spec.ts.snap b/test/jest/unit/lib/formatters/test/__snapshots__/display-result.spec.ts.snap index 7840bd34f3..8e55603ffb 100644 --- a/test/jest/unit/lib/formatters/test/__snapshots__/display-result.spec.ts.snap +++ b/test/jest/unit/lib/formatters/test/__snapshots__/display-result.spec.ts.snap @@ -6,14 +6,14 @@ Testing src... ✗ High severity vulnerability found in musl Description: Out-of-bounds Write - Info: [URL] + Info: URL Introduced through: meta-common-packages@meta From: meta-common-packages@meta > musl@1.1.19-r10 Fixed in: 1.1.19-r11 ✗ High severity vulnerability found in expat Description: XML External Entity (XXE) Injection - Info: [URL] + Info: URL Introduced through: expat@2.2.5-r0, .python-rundeps@0, git@2.18.2-r0 From: expat@2.2.5-r0 From: .python-rundeps@0 > expat@2.2.5-r0 @@ -25,7 +25,7 @@ Testing src... ✗ High severity vulnerability found in expat Description: XML External Entity (XXE) Injection - Info: [URL] + Info: URL Introduced through: expat@2.2.5-r0, .python-rundeps@0, git@2.18.2-r0 From: expat@2.2.5-r0 From: .python-rundeps@0 > expat@2.2.5-r0 @@ -58,14 +58,14 @@ Testing src... ✗ High severity vulnerability found in musl Description: Out-of-bounds Write - Info: [URL] + Info: URL Introduced through: meta-common-packages@meta From: meta-common-packages@meta > musl@1.1.19-r10 Fixed in: 1.1.19-r11 ✗ High severity vulnerability found in expat Description: XML External Entity (XXE) Injection - Info: [URL] + Info: URL Introduced through: expat@2.2.5-r0, .python-rundeps@0, git@2.18.2-r0 From: expat@2.2.5-r0 From: .python-rundeps@0 > expat@2.2.5-r0 @@ -77,7 +77,7 @@ Testing src... ✗ High severity vulnerability found in expat Description: XML External Entity (XXE) Injection - Info: [URL] + Info: URL Introduced through: expat@2.2.5-r0, .python-rundeps@0, git@2.18.2-r0 From: expat@2.2.5-r0 From: .python-rundeps@0 > expat@2.2.5-r0 @@ -106,7 +106,7 @@ Testing alpine:latest... ✗ High severity vulnerability found in musl Description: Out-of-bounds Write - Info: [URL] + Info: URL Introduced through: meta-common-packages@meta From: meta-common-packages@meta > musl@1.1.19-r10 Fixed in: 1.1.19-r11 @@ -139,7 +139,7 @@ Testing alpine:latest... ✗ High severity vulnerability found in musl Description: Out-of-bounds Write - Info: [URL] + Info: URL Introduced through: meta-common-packages@meta From: meta-common-packages@meta > musl@1.1.19-r10 Fixed in: 1.1.19-r11 @@ -172,14 +172,14 @@ Testing src... ✗ High severity vulnerability found in musl Description: Out-of-bounds Write - Info: [URL] + Info: URL Introduced through: meta-common-packages@meta From: meta-common-packages@meta > musl@1.1.19-r10 Fixed in: 1.1.19-r11 ✗ High severity vulnerability found in expat Description: XML External Entity (XXE) Injection - Info: [URL] + Info: URL Introduced through: expat@2.2.5-r0, .python-rundeps@0, git@2.18.2-r0 From: expat@2.2.5-r0 From: .python-rundeps@0 > expat@2.2.5-r0 @@ -191,7 +191,7 @@ Testing src... ✗ High severity vulnerability found in expat Description: XML External Entity (XXE) Injection - Info: [URL] + Info: URL Introduced through: expat@2.2.5-r0, .python-rundeps@0, git@2.18.2-r0 From: expat@2.2.5-r0 From: .python-rundeps@0 > expat@2.2.5-r0 @@ -223,7 +223,7 @@ Base Image Vulnerabilities Severity ubuntu:impish-20210928 13 0 critical, 0 high, 2 medium, 11 low -Learn more: [URL]" +Learn more: URL" `; exports[`displayResult Pip result with pins 1`] = ` @@ -236,10 +236,10 @@ Tested 2 dependencies for known issues, found 32 issues, 2 vulnerable paths. Issues with no direct upgrade or patch (1 issue): ✗ [Low] Directory Traversal - [URL] in django@1.6.1 - introduced by: - django@1.6.1 - This issue was fixed in versions: 2.2.18, 3.0.12, 3.1.6 + Info: https://security.snyk.io/vuln/SNYK-PYTHON-DJANGO-1066259 + Introduced through: django@1.6.1 + Introduced by: django@1.6.1 + Fixed in: 2.2.18, 3.0.12, 3.1.6 Issues to fix by upgrading dependencies (1 issue): @@ -247,9 +247,9 @@ Issues to fix by upgrading dependencies (1 issue): Upgrade django@1.6.1 to django@2.2.18 to fix 1 issue ✗ [Medium] Content Spoofing - [URL] in django@1.6.1 - introduced by: - django@1.6.1 + Info: https://security.snyk.io/vuln/SNYK-PYTHON-DJANGO-72888 + Introduced through: django@1.6.1 + Introduced by: django@1.6.1 @@ -261,6 +261,11 @@ Open source: no Project path: src Licenses: enabled +Test summary: + + 1 issues with no upgrade or patch + 1 fixable issues: 1 Medium + Tip: Try \`snyk fix\` to address these issues.\`snyk fix\` is a new CLI command in that aims to automatically apply the recommended updates for supported ecosystems. See documentation on how to enable this beta feature: https://docs.snyk.io/snyk-cli/fix-vulnerabilities-from-the-cli/automatic-remediation-with-snyk-fix#enabling-snyk-fix @@ -279,9 +284,9 @@ Patchable issues (1 issue): Patch available for node-uuid@1.4.0 ✗ [Low (originally Medium)] Insecure Randomness - [URL] in node-uuid@1.4.0 - introduced by: - node-uuid@1.4.0 + Info: https://security.snyk.io/vuln/npm:node-uuid:20160328 + Introduced through: node-uuid@1.4.0 + Introduced by: node-uuid@1.4.0 Issues to fix by upgrading (3 issues): @@ -289,19 +294,19 @@ Issues to fix by upgrading (3 issues): Upgrade qs@0.0.6 to qs@6.0.4 to fix 3 issues ✗ [Low (originally High)] Prototype Override Protection Bypass - [URL] in qs@0.0.6 - introduced by: - qs@0.0.6 + Info: https://security.snyk.io/vuln/npm:qs:20170213 + Introduced through: qs@0.0.6 + Introduced by: qs@0.0.6 ✗ [Low (originally High)] Denial of Service (DoS) - [URL] in qs@0.0.6 - introduced by: - qs@0.0.6 + Info: https://security.snyk.io/vuln/npm:qs:20140806 + Introduced through: qs@0.0.6 + Introduced by: qs@0.0.6 ✗ [Low (originally Medium)] Denial of Service (DoS) - [URL] in qs@0.0.6 - introduced by: - qs@0.0.6 + Info: https://security.snyk.io/vuln/npm:qs:20140806-1 + Introduced through: qs@0.0.6 + Introduced by: qs@0.0.6 @@ -312,6 +317,10 @@ Project name: shallow-goof Open source: no Project path: src +Test summary: + + 4 fixable issues: 3 Low + Tip: Detected multiple supported manifests (3), use --all-projects to scan all of them at once." `; @@ -325,9 +334,9 @@ Tested 3 dependencies for known issues, found 6 issues, 8 vulnerable paths. License issues (1 issue): ✗ [High] Unknown license - [URL] in rack-cache@1.1 - introduced by: - rack-cache@1.1 + Info: https://dev.snyk.io/vuln/snyk:lic:rubygems:rack-cache:Unknown + Introduced through: rack-cache@1.1 + Introduced by: rack-cache@1.1 Legal instructions: ○ for LGPL-3.0 license: I am legal license instruction @@ -337,49 +346,43 @@ Issues to fix by upgrading (7 issues): Upgrade rack@1.6.5 to rack@1.6.11 to fix 1 issue ✗ [Medium] Cross-site Scripting (XSS) - [URL] in rack@1.6.5 - introduced by: - rack@1.6.5 - rack-cache@1.1 > rack@1.6.5 - rack-protection@1.5.3 > rack@1.6.5 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACK-72567 + Introduced through: rack@1.6.5 + Introduced by: rack@1.6.5 > rack-cache@1.1 > rack@1.6.5 > rack-protection@1.5.3 > rack@1.6.5 Upgrade rack-cache@1.1 to rack-cache@1.3.0 to fix 2 issues ✗ [Medium] Cross-site Scripting (XSS) - [URL] in rack@1.6.5 - introduced by: - rack@1.6.5 - rack-cache@1.1 > rack@1.6.5 - rack-protection@1.5.3 > rack@1.6.5 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACK-72567 + Introduced through: rack@1.6.5 + Introduced by: rack@1.6.5 > rack-cache@1.1 > rack@1.6.5 > rack-protection@1.5.3 > rack@1.6.5 ✗ [High] HTTP Header Caching Weakness - [URL] in rack-cache@1.1 - introduced by: - rack-cache@1.1 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACKCACHE-20031 + Introduced through: rack-cache@1.1 + Introduced by: rack-cache@1.1 Upgrade rack-protection@1.5.3 to rack-protection@2.0.0 to fix 4 issues ✗ [Low] Side-channel attack - [URL] in rack-protection@1.5.3 - introduced by: - rack-protection@1.5.3 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACKPROTECTION-20394 + Introduced through: rack-protection@1.5.3 + Introduced by: rack-protection@1.5.3 ✗ [Medium] Timing Attack - [URL] in rack-protection@1.5.3 - introduced by: - rack-protection@1.5.3 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACKPROTECTION-20395 + Introduced through: rack-protection@1.5.3 + Introduced by: rack-protection@1.5.3 ✗ [Medium] Directory Traversal - [URL] in rack-protection@1.5.3 - introduced by: - rack-protection@1.5.3 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACKPROTECTION-22019 + Introduced through: rack-protection@1.5.3 + Introduced by: rack-protection@1.5.3 ✗ [Medium] Cross-site Scripting (XSS) - [URL] in rack@1.6.5 - introduced by: - rack@1.6.5 - rack-cache@1.1 > rack@1.6.5 - rack-protection@1.5.3 > rack@1.6.5 + Info: https://security.snyk.io/vuln/SNYK-RUBY-RACK-72567 + Introduced through: rack@1.6.5 + Introduced by: rack@1.6.5 > rack-cache@1.1 > rack@1.6.5 > rack-protection@1.5.3 > rack@1.6.5 @@ -389,5 +392,10 @@ Open source: no Project path: src Licenses: enabled +Test summary: + + 1 license issues: 1 High + 7 fixable issues: 1 High, 5 Medium, 1 Low + Tip: Detected multiple supported manifests (3), use --all-projects to scan all of them at once." `; diff --git a/test/jest/unit/lib/formatters/test/display-result.spec.ts b/test/jest/unit/lib/formatters/test/display-result.spec.ts index aeddc5bec6..455f7a5273 100644 --- a/test/jest/unit/lib/formatters/test/display-result.spec.ts +++ b/test/jest/unit/lib/formatters/test/display-result.spec.ts @@ -18,7 +18,7 @@ describe('displayResult', () => { { showVulnPaths: 'all', path: 'src', docker: true }, 3, ); - expect(stripAnsi(res).replace(/http.*/g, '[URL]')).toMatchSnapshot(); + expect(stripAnsi(res).replace(/http.*/g, 'URL')).toMatchSnapshot(); }); it('Docker test result no file path and base image auto detected', () => { @@ -38,7 +38,7 @@ describe('displayResult', () => { { showVulnPaths: 'all', path: 'src', docker: true }, 3, ); - expect(stripAnsi(res).replace(/http.*/g, '[URL]')).toMatchSnapshot(); + expect(stripAnsi(res).replace(/http.*/g, 'URL')).toMatchSnapshot(); }); it('Docker test result with base image non resolvable warning', () => { @@ -61,7 +61,7 @@ describe('displayResult', () => { }, 1, ); - expect(stripAnsi(res).replace(/http.*/g, '[URL]')).toMatchSnapshot(); + expect(stripAnsi(res).replace(/http.*/g, 'URL')).toMatchSnapshot(); }); it('Docker test result with base image name not found warning', () => { @@ -84,7 +84,7 @@ describe('displayResult', () => { }, 1, ); - expect(stripAnsi(res).replace(/http.*/g, '[URL]')).toMatchSnapshot(); + expect(stripAnsi(res).replace(/http.*/g, 'URL')).toMatchSnapshot(); }); it('Docker test result with remediation advice', () => { @@ -102,7 +102,7 @@ describe('displayResult', () => { { showVulnPaths: 'all', path: 'src', docker: true }, 3, ); - expect(stripAnsi(res).replace(/http.*/g, '[URL]')).toMatchSnapshot(); + expect(stripAnsi(res).replace(/http.*/g, 'URL')).toMatchSnapshot(); }); it('Pip result with pins', () => { @@ -118,8 +118,7 @@ describe('displayResult', () => { { showVulnPaths: 'all', path: 'src' }, 3, ); - - expect(stripAnsi(res).replace(/\[http.*\]/g, '[URL]')).toMatchSnapshot(); + expect(stripAnsi(res).replace(/\[http.*\]/g, 'URL')).toMatchSnapshot(); }); it('with license issues', () => { @@ -137,7 +136,7 @@ describe('displayResult', () => { { showVulnPaths: 'all', path: 'src' }, 3, ); - expect(stripAnsi(res).replace(/\[http.*\]/g, '[URL]')).toMatchSnapshot(); + expect(stripAnsi(res).replace(/\[http.*\]/g, 'URL')).toMatchSnapshot(); }); it('with Upgrades & Patches', () => { @@ -155,6 +154,6 @@ describe('displayResult', () => { { showVulnPaths: 'all', path: 'src' }, 3, ); - expect(stripAnsi(res).replace(/\[http.*\]/g, '[URL]')).toMatchSnapshot(); + expect(stripAnsi(res).replace(/\[http.*\]/g, 'URL')).toMatchSnapshot(); }); }); diff --git a/test/tap/display-test-results.test.ts b/test/tap/display-test-results.test.ts index 5592c93649..a7f8530435 100644 --- a/test/tap/display-test-results.test.ts +++ b/test/tap/display-test-results.test.ts @@ -30,11 +30,7 @@ test('`test ruby-app` remediation displayed', async (t) => { 'upgrade advice displayed', ); t.match(res, 'Tested 52 dependencies for known issues'); - t.match( - res, - 'This issue was fixed in versions: 1.2.3', - 'fixed in is shown', - ); + t.match(res, 'Fixed in: 1.2.3', 'fixed in is shown'); t.match( res, 'No upgrade or patch available', @@ -103,7 +99,6 @@ test('`test npm-package-with-severity-override` show original severity upgrade', const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse); try { - console.log('David'); await cli.test('npm-package-with-severity-override'); } catch (error) { const { message } = error;