-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: adding manifest file to vuln card if scanning multi-project
- Loading branch information
Showing
3 changed files
with
78 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,15 +4,13 @@ import * as isEmpty from 'lodash.isempty'; | |
import * as orderBy from 'lodash.orderby'; | ||
import chalk from 'chalk'; | ||
import * as debugModule from 'debug'; | ||
import { addIssueDataToPatch, getUpgrades, IacProjectType, severityMap } from './vuln'; | ||
import { processSourceCode, } from './codeutil'; | ||
import fs = require('fs'); | ||
import Handlebars = require('handlebars'); | ||
import marked = require('marked'); | ||
import moment = require('moment'); | ||
import path = require('path'); | ||
import { addIssueDataToPatch, getUpgrades, severityMap, IacProjectType } from './vuln'; | ||
import { | ||
processSourceCode, | ||
} from './codeutil'; | ||
|
||
const debug = debugModule('snyk-to-html'); | ||
|
||
|
@@ -31,8 +29,8 @@ function readFile(filePath: string, encoding: string): Promise<string> { | |
|
||
function handleInvalidJson(reason: any) { | ||
if (reason.isInvalidJson) { | ||
reason.message = reason.message + 'Error running `snyk-to-html`. Please check you are providing the correct parameters. ' + | ||
'Is the issue persists contact [email protected]'; | ||
reason.message = reason.message + 'Error running `snyk-to-html`. Please check you are providing the correct parameters. ' + | ||
'Is the issue persists contact [email protected]'; | ||
} | ||
console.log(reason.message); | ||
} | ||
|
@@ -43,7 +41,7 @@ function promisedParseJSON(json) { | |
resolve(JSON.parse(json)); | ||
} catch (error) { | ||
error.message = chalk.red.bold('The source provided is not a valid json! Please validate that the input provided to the CLI is an actual JSON\n\n' + | ||
'Tip: To find more information, try running `snyk-to-html` in debug mode by appending to the CLI the `-d` parameter\n\n'); | ||
'Tip: To find more information, try running `snyk-to-html` in debug mode by appending to the CLI the `-d` parameter\n\n'); | ||
debug(`Input provided to the CLI: \n${json}\n\n`); | ||
error.isInvalidJson = true; | ||
reject(error); | ||
|
@@ -99,7 +97,7 @@ class SnykToHtml { | |
export { SnykToHtml }; | ||
|
||
function metadataForVuln(vuln: any) { | ||
let {cveSpaced, cveLineBreaks} = concatenateCVEs(vuln) | ||
let { cveSpaced, cveLineBreaks } = concatenateCVEs(vuln) | ||
|
||
return { | ||
id: vuln.id, | ||
|
@@ -126,18 +124,18 @@ function concatenateCVEs(vuln: any) { | |
let cveLineBreaks = '' | ||
|
||
if (vuln.identifiers) { | ||
vuln.identifiers.CVE.forEach(function(c) { | ||
vuln.identifiers.CVE.forEach(function (c) { | ||
let cveLink = `<a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=${c}">${c}</a>` | ||
cveSpaced += `${cveLink} ` | ||
cveLineBreaks += `${cveLink}</br>` | ||
}) | ||
} | ||
|
||
return {cveSpaced, cveLineBreaks} | ||
return { cveSpaced, cveLineBreaks } | ||
} | ||
|
||
function dateFromDateTimeString(dateTimeString: string) { | ||
return dateTimeString.substr(0,10); | ||
return dateTimeString.substr(0, 10); | ||
} | ||
|
||
function groupVulns(vulns) { | ||
|
@@ -148,7 +146,7 @@ function groupVulns(vulns) { | |
if (vulns && Array.isArray(vulns)) { | ||
vulns.map(vuln => { | ||
if (!result[vuln.id]) { | ||
result[vuln.id] = {list: [vuln], metadata: metadataForVuln(vuln)}; | ||
result[vuln.id] = { list: [vuln], metadata: metadataForVuln(vuln) }; | ||
pathsCount++; | ||
uniqueCount++; | ||
} else { | ||
|
@@ -180,12 +178,12 @@ async function generateTemplate(data: any, | |
template: string, | ||
showRemediation: boolean, | ||
summary: boolean): | ||
Promise<string> { | ||
Promise<string> { | ||
if (showRemediation && data.remediation) { | ||
data.showRemediations = showRemediation; | ||
const {upgrade, pin, unresolved, patch} = data.remediation; | ||
const { upgrade, pin, unresolved, patch } = data.remediation; | ||
data.anyRemediations = !isEmpty(upgrade) || | ||
!isEmpty(patch) || !isEmpty(pin); | ||
!isEmpty(patch) || !isEmpty(pin); | ||
data.anyUnresolved = !!unresolved?.vulnerabilities; | ||
data.unresolved = groupVulns(unresolved); | ||
data.upgrades = getUpgrades(upgrade, data.vulnerabilities); | ||
|
@@ -206,7 +204,7 @@ async function generateTemplate(data: any, | |
data.uniqueCount = vulnMetadata.vulnerabilitiesUniqueCount; | ||
data.summary = vulnMetadata.vulnerabilitiesPathsCount + ' vulnerable dependency paths'; | ||
data.showSummaryOnly = summary; | ||
if(data.paths?.length === 1){ | ||
if (data.paths?.length === 1) { | ||
data.packageManager = data.paths[0].packageManager; | ||
} | ||
|
||
|
@@ -256,15 +254,34 @@ async function generateCodeTemplate( | |
} | ||
|
||
function mergeData(dataArray: any[]): any { | ||
const vulnsArrays = dataArray.map(project => project.vulnerabilities || []); | ||
const vulnsArrays = dataArray.map((project) => { | ||
if (!project.vulnerabilities) { | ||
return []; | ||
} | ||
|
||
// Add project data to each of the vulnerabilities to display more | ||
// details on each vulnerability card, in order to properly distinguish | ||
// from which project a vuln is connected, in case of displaying multiple | ||
// projects. | ||
const vulns = project.vulnerabilities.map((vuln) => ({ | ||
...vuln, | ||
displayTargetFile: project.displayTargetFile, | ||
path: project.path | ||
})); | ||
return vulns; | ||
}); | ||
const aggregateVulnerabilities = [].concat(...vulnsArrays); | ||
|
||
const totalUniqueCount = | ||
dataArray.reduce((acc, item) => acc + item.vulnerabilities.length || 0, 0); | ||
const totalDepCount = | ||
dataArray.reduce((acc, item) => acc + item.dependencyCount || 0, 0); | ||
|
||
const paths = dataArray.map(project => ({ path: project.path, packageManager: project.packageManager })); | ||
const paths = dataArray.map(project => ({ | ||
path: project.path, | ||
packageManager: project.packageManager, | ||
displayTargetFile: project.displayTargetFile, | ||
})); | ||
|
||
return { | ||
vulnerabilities: aggregateVulnerabilities, | ||
|
@@ -285,7 +302,7 @@ async function processIacData(data: any, template: string, summary: boolean): Pr | |
return generateIacTemplate(data, template); | ||
} | ||
|
||
const dataArray = Array.isArray(data)? data : [data]; | ||
const dataArray = Array.isArray(data) ? data : [data]; | ||
dataArray.forEach(project => { | ||
project.infrastructureAsCodeIssues.forEach(issue => { | ||
issue.severityValue = severityMap[issue.severity]; | ||
|
@@ -325,7 +342,7 @@ async function processCodeData( | |
const dataArray = Array.isArray(data) ? data : [data]; | ||
|
||
const OrderedIssuesArray = await processSourceCode(dataArray); | ||
|
||
const totalIssues = dataArray[0].runs[0].results.length; | ||
const processedData = { | ||
projects: OrderedIssuesArray, | ||
|
@@ -368,34 +385,43 @@ const hh = { | |
// block helpers | ||
/* tslint:disable:only-arrow-functions */ | ||
/* tslint:disable:object-literal-shorthand */ | ||
isDoubleArray: function(data, options) { | ||
isDoubleArray: function (data, options) { | ||
return Array.isArray(data[0]) ? options.fn(data) : options.inverse(data); | ||
}, | ||
if_eq: function(this: void, a, b, opts) { | ||
if_eq: function (this: void, a, b, opts) { | ||
return (a === b) ? opts.fn(this) : opts.inverse(this); | ||
}, | ||
if_gt: function(this: void, a, b, opts) { | ||
if_gt: function (this: void, a, b, opts) { | ||
return (a > b) ? opts.fn(this) : opts.inverse(this); | ||
}, | ||
if_not_eq: function(this: void, a, b, opts) { | ||
if_not_eq: function (this: void, a, b, opts) { | ||
return (a !== b) ? opts.fn(this) : opts.inverse(this); | ||
}, | ||
if_any: function(this: void, opts, ...args) { | ||
if_any: function (this: void, opts, ...args) { | ||
return args.some(v => !!v) ? opts.fn(this) : opts.inverse(this); | ||
}, | ||
ifCond: function(this: void, v1, operator, v2, options) { | ||
ifCond: function (this: void, v1, operator, v2, options) { | ||
const choose = (pred: boolean) => pred ? options.fn(this) : options.inverse(this); | ||
switch (operator) { | ||
// tslint:disable-next-line:triple-equals | ||
case '==': return choose(v1 == v2); | ||
case '===': return choose(v1 === v2); | ||
case '<': return choose(v1 < v2); | ||
case '<=': return choose(v1 <= v2); | ||
case '>': return choose(v1 > v2); | ||
case '>=': return choose(v1 >= v2); | ||
case '&&': return choose(v1 && v2); | ||
case '||': return choose(v1 || v2); | ||
default: return choose(false); | ||
case '==': | ||
return choose(v1 == v2); | ||
case '===': | ||
return choose(v1 === v2); | ||
case '<': | ||
return choose(v1 < v2); | ||
case '<=': | ||
return choose(v1 <= v2); | ||
case '>': | ||
return choose(v1 > v2); | ||
case '>=': | ||
return choose(v1 >= v2); | ||
case '&&': | ||
return choose(v1 && v2); | ||
case '||': | ||
return choose(v1 || v2); | ||
default: | ||
return choose(false); | ||
} | ||
}, | ||
getRemediation: (description, fixedIn) => { | ||
|
@@ -416,7 +442,7 @@ const hh = { | |
severityLabel: (severity: string) => { | ||
return severity[0].toUpperCase(); | ||
}, | ||
startsWith: function(str, start, options) { | ||
startsWith: function (str, start, options) { | ||
return str.startsWith(start) ? options.fn(this) : options.inverse(this); | ||
}, | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters