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

Add HTML exporting feature for reports #183

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor, report: migrating filter formatting functions to utils, imp…
…lement filtering into html report.
  • Loading branch information
mster committed Aug 30, 2019
commit d35e6490f7fc5d318cead33555a4b70c356313e6
39 changes: 32 additions & 7 deletions lib/report/html-template.js
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ const {

module.exports = renderHTML

function renderHTML (title, summary, report, whitelist) {
function renderHTML (title, summary, report, reportLength, whitelist, whitelistLength, formattedFilterOptions) {
const { riskCount, securityCount, insecureModules, complianceCount } = summary

let alternate = false
@@ -162,7 +162,7 @@ function renderHTML (title, summary, report, whitelist) {

<div id="summary" class="bottom-20 left-20">
<span class="subtitle">Summary</span>
<p><b class="white">${report.length}</b> packages checked</p>
<p><b class="white">${reportLength}</b> packages checked</p>
<br>
<p><span class="red"><b>${riskCount[4]}</b> Critical Risk</span></p>
<p><span class="orange"><b>${riskCount[3]}</b> High Risk</span></p>
@@ -181,15 +181,27 @@ function renderHTML (title, summary, report, whitelist) {
? `<b class="white">${complianceCount}</b> noncompliant modules found`
: '<span class="green">✓</span> All modules compliant')}
</p>
${(whitelist.length > 0
? `<p><b class="white">${whitelist.length}</b> used modules whitelisted</p>`
${(whitelistLength > 0
? `<p><b class="white">${whitelistLength}</b> used modules whitelisted</p>`
: '')}
</div>

${(whitelist.length > 0
${(whitelistLength > 0
? `
<div id="whitelist-list">
<span class="subtitle">Whitelisted Modules</span>
<p>
<span class="subtitle">
Whitelisted
${(formattedFilterOptions.length > 9
? 'Filtered'
: '')}
Modules
</span>
${(formattedFilterOptions.length > 9
? `(${formattedFilterOptions})`
: '')}

</p>
<hr>
<table id="whitelist-table" class="bottom-20">
<tr style="margin-bottom:5px;">
@@ -205,7 +217,20 @@ function renderHTML (title, summary, report, whitelist) {
: '')}

<div id="module-list">
<p class="subtitle">${(whitelist.length > 0 ? 'Non-Whitelisted ' : '')}Modules</p>
<p>
<span class="subtitle">
${(whitelistLength > 0
? 'Non-Whitelisted'
: '')}
${(formattedFilterOptions.length > 9
? 'Filtered'
: '')}
Modules
</span>
${(formattedFilterOptions.length > 9
? `( ${formattedFilterOptions} )`
: '')}
</p>
<hr>
<table id="module-table" class="bottom-20">
<tr style="margin-bottom:5px;">
23 changes: 20 additions & 3 deletions lib/report/html.js
Original file line number Diff line number Diff line change
@@ -8,14 +8,18 @@ const {
formatError
} = require('../ncm-style')
const {
summaryInfo
summaryInfo,
moduleSort,
filterReport,
parseFilterOptions,
formatFilterOptions
} = require('./util')
const renderTemplate = require('./html-template')
const L = console.log

module.exports = htmlReport

async function htmlReport (report, whitelist, dir, output) {
async function htmlReport (report, whitelist, dir, output, argv) {
/* Output may only use the `.html` file format */
if (output !== true && !(/^.*\.html$/.test(path.basename(output)))) {
L()
@@ -27,12 +31,25 @@ async function htmlReport (report, whitelist, dir, output) {

const title = `${path.basename(dir) || 'NCM'}`
const summary = summaryInfo(report) // { riskCount, insecureModules, complianceCount, securityCount }
const reportLength = report.length
const whitelistLength = whitelist.length

const filterOptions = parseFilterOptions(argv)
const formattedfilterOptions = formatFilterOptions(filterOptions)
report = filterReport(report, filterOptions)
report = moduleSort(report)

whitelist = filterReport(whitelist, filterOptions)
whitelist = moduleSort(whitelist)

const htmlData = renderTemplate(
title,
summary,
report,
whitelist
reportLength,
whitelist,
whitelistLength,
formattedfilterOptions
)

/*
59 changes: 7 additions & 52 deletions lib/report/short.js
Original file line number Diff line number Diff line change
@@ -3,7 +3,11 @@
module.exports = shortReport

const summary = require('./summary')
const { moduleList, SEVERITY_RMAP } = require('./util')
const {
moduleList,
parseFilterOptions,
formatFilterOptions
} = require('./util')

const {
COLORS,
@@ -13,39 +17,7 @@ const chalk = require('chalk')
const L = console.log

function shortReport (report, whitelist, dir, argv) {
let filterSecurity = argv ? !!argv.security : false
let filterCompliance = argv ? !!argv.compliance : false
let filterLevel = SEVERITY_RMAP.indexOf('NONE')

if (argv.filter) {
const segments = argv.filter.split(',')
.map(s => s.trim().toLowerCase())

if (segments.includes('compliance')) {
filterCompliance = true
}
if (segments.includes('security')) {
filterSecurity = true
}
if (segments.includes('c') || segments.includes('critical')) {
filterLevel = SEVERITY_RMAP.indexOf('CRITICAL')
}
if (segments.includes('h') || segments.includes('high')) {
filterLevel = SEVERITY_RMAP.indexOf('HIGH')
}
if (segments.includes('m') || segments.includes('medium')) {
filterLevel = SEVERITY_RMAP.indexOf('MEDIUM')
}
if (segments.includes('l') || segments.includes('low')) {
filterLevel = SEVERITY_RMAP.indexOf('LOW')
}
}

const filterOptions = {
filterCompliance: filterCompliance,
filterSecurity: filterSecurity,
filterLevel: filterLevel
}
const filterOptions = parseFilterOptions(argv)

summary(report, dir, filterOptions)

@@ -55,7 +27,7 @@ function shortReport (report, whitelist, dir, argv) {
L()
}

if (filterCompliance || filterSecurity || filterLevel > 0) {
if (filterOptions.filterCompliance || filterOptions.filterSecurity || filterOptions.filterLevel > 0) {
const filterFormat = formatFilterOptions(filterOptions)
if (whitelist.length > 0) {
moduleList(
@@ -80,20 +52,3 @@ function shortReport (report, whitelist, dir, argv) {
moduleList(report.slice(0, 5), 'Top 5: Highest Risk Modules')
}
}

function formatFilterOptions (filterOptions) {
let str = '--filter='
if (filterOptions.filterCompliance) {
str += 'compliance,'
}
if (filterOptions.filterSecurity) {
str += 'security,'
}
if (filterOptions.filterLevel) {
str += SEVERITY_RMAP[filterOptions.filterLevel] + ','
}
if (str[str.length - 1] === ',') {
str = str.slice(0, str.length - 1)
}
return str
}
60 changes: 59 additions & 1 deletion lib/report/util.js
Original file line number Diff line number Diff line change
@@ -42,7 +42,10 @@ module.exports = {
moduleList,
moduleSort,
summaryInfo,
filterVulns
filterVulns,
filterReport,
parseFilterOptions,
formatFilterOptions
}

function filterReport (report, options) {
@@ -288,3 +291,58 @@ function filterVulns (failures) {

return vulns
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Migration of formatting logic for reusability in the HTML reporting feature.


function parseFilterOptions (argv) {
let filterSecurity = argv ? !!argv.security : false
let filterCompliance = argv ? !!argv.compliance : false
let filterLevel = SEVERITY_RMAP.indexOf('NONE')

if (argv.filter) {
const segments = argv.filter.split(',')
.map(s => s.trim().toLowerCase())

if (segments.includes('compliance')) {
filterCompliance = true
}
if (segments.includes('security')) {
filterSecurity = true
}
if (segments.includes('c') || segments.includes('critical')) {
filterLevel = SEVERITY_RMAP.indexOf('CRITICAL')
}
if (segments.includes('h') || segments.includes('high')) {
filterLevel = SEVERITY_RMAP.indexOf('HIGH')
}
if (segments.includes('m') || segments.includes('medium')) {
filterLevel = SEVERITY_RMAP.indexOf('MEDIUM')
}
if (segments.includes('l') || segments.includes('low')) {
filterLevel = SEVERITY_RMAP.indexOf('LOW')
}
}

const filterOptions = {
filterCompliance: filterCompliance,
filterSecurity: filterSecurity,
filterLevel: filterLevel
}

return filterOptions
}

function formatFilterOptions (filterOptions) {
let str = '--filter='
if (filterOptions.filterCompliance) {
str += 'compliance,'
}
if (filterOptions.filterSecurity) {
str += 'security,'
}
if (filterOptions.filterLevel) {
str += SEVERITY_RMAP[filterOptions.filterLevel] + ','
}
if (str[str.length - 1] === ',') {
str = str.slice(0, str.length - 1)
}
return str
}