Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

provide severity option #39

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
109 changes: 94 additions & 15 deletions lib/utils.js
@@ -1,13 +1,8 @@
'use strict'

exports.severityLabel = severityLabel
exports.color = color
exports.totalVulnCount = totalVulnCount
exports.severities = severities

const ccs = require('console-control-strings')

const severityColors = {
const severityMetadata = {
critical: {
color: 'brightMagenta',
label: 'Critical'
Expand All @@ -29,32 +24,116 @@ const severityColors = {
label: 'Info'
}
}
const severityOrder = ['critical', 'high', 'moderate', 'low', 'info']
severityOrder.forEach((severity, order) => {
severityMetadata[severity].order = order
})

function color (value, colorName, withColor) {
const color = exports.color = function (value, colorName, withColor) {
return (colorName && withColor) ? ccs.color(colorName) + value + ccs.color('reset') : value
}

function severityLabel (sev, withColor, bold) {
if (!(sev in severityColors)) return sev.charAt(0).toUpperCase() + sev.substr(1).toLowerCase()
let colorName = severityColors[sev].color
const severityLabel = exports.severityLabel = function (sev, withColor, bold) {
if (!(sev in severityMetadata)) return sev.charAt(0).toUpperCase() + sev.substr(1).toLowerCase()
let colorName = severityMetadata[sev].color
if (bold) colorName = [colorName, 'bold']
return color(severityColors[sev].label, colorName, withColor)
return color(severityMetadata[sev].label, colorName, withColor)
}

const severityCompare = exports.severityCompare = function (a, b) {
a = a.severity || a
b = b.severity || b
const oA = a in severityMetadata ? severityMetadata[a].order : -1
const oB = b in severityMetadata ? severityMetadata[b].order : -1
return oA - oB
}

function totalVulnCount (vulns) {
return Object.keys(vulns).reduce((accumulator, key) => {
const vulnCount = vulns[key]
exports.vulnTotal = function (vulns) {
return Object.keys(vulns).reduce((accumulator, severity) => {
const vulnCount = vulns[severity]
accumulator += vulnCount

return accumulator
}, 0)
}

function severities (vulns) {
exports.vulnSummary = function (vulns, config) {
config = Object.assign({
excludeDev: false,
excludeProd: false,
severityThreshold: 'info'
}, config)
const summary = {
total: 0
}

const sev = Object.keys(vulns).reduce((accumulator, severity) => {
const excludeSeverity = severityCompare(config.severityThreshold, severity) < 0

if (!excludeSeverity) {
const vulnCount = vulns[severity]
if (vulnCount > 0) {
summary.total += vulnCount
accumulator.push(`${vulnCount} ${severityLabel(severity, config.withColor).toLowerCase()}`)
}
}

return accumulator
}, [])

if (summary.total === 0) {
summary.msg = `found ${color('0', 'brightGreen', config.withColor)} vulnerabilities`
} else if (sev.length === 1) {
summary.msg = `found ${sev[0]} severity vulnerabilit${summary.total === 1 ? 'y' : 'ies'}`
} else {
summary.msg = `found ${color(summary.total, 'brightRed', config.withColor)} vulnerabilities (${sev.join(', ')})`
}

return summary
}

exports.vulnFilter = function (data, config) {
config = Object.assign({
excludeDev: false,
excludeProd: false,
severityThreshold: 'info'
}, config)
data.actions.forEach((action) => {
action.resolves = action.resolves.filter(({id, dev}) => {
const severity = data.advisories[id].severity
const excludeSeverity = severityCompare(config.severityThreshold, severity) < 0
const exclude = config[dev ? 'excludeDev' : 'excludeProd'] || excludeSeverity
if (exclude) {
data.metadata.vulnerabilities[severity]--
data.metadata.excluded = data.metadata.excluded || {}
data.metadata.excluded[severity] = (data.metadata.excluded[severity] || 0) + 1
}
return !exclude
})
})
}

exports.severities = function (vulns) {
return Object.keys(vulns).reduce((accumulator, severity) => {
const vulnCount = vulns[severity]
if (vulnCount > 0) accumulator.push([severity, vulnCount])

return accumulator
}, [])
}

exports.getRecommendation = function (action, config) {
if (action.action === 'install') {
const isDev = action.resolves[0].dev

return {
cmd: `npm install ${isDev ? '--save-dev ' : ''}${action.module}@${action.target}`,
isBreaking: action.isMajor
}
} else {
return {
cmd: `npm update ${action.module} --depth ${action.depth}`,
isBreaking: false
}
}
}
48 changes: 38 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "npm-audit-report",
"version": "1.3.2",
"version": "1.3.3",
"description": "Given a response from the npm security api, render it into a variety of security reports",
"main": "index.js",
"scripts": {
Expand Down