diff --git a/index.ts b/index.ts index 5ab2838..655afeb 100755 --- a/index.ts +++ b/index.ts @@ -6,6 +6,7 @@ import { exec } from 'child_process'; import { AuditLevel, CommandOptions } from 'src/types'; import handleInput from './src/handlers/handleInput'; +import type { HandleInputCallback } from './src/handlers/handleInput'; import handleFinish from './src/handlers/handleFinish'; import packageJson from './package.json'; @@ -20,14 +21,18 @@ const program = new Command(); * @param {Array} exceptionIds List of vulnerability IDs to exclude * @param {Array} modulesToIgnore List of vulnerable modules to ignore in audit results * @param {Array} columnsToInclude List of columns to include in audit results + * @param {Boolean} outputJson Output audit report in JSON format + * @param {Array} exceptionsReport Exceptions report */ -export function callback( +export const callback: HandleInputCallback = ( auditCommand: string, auditLevel: AuditLevel, exceptionIds: string[], modulesToIgnore: string[], columnsToInclude: string[], -): void { + outputJson: boolean, + exceptionsReport: string[][], +): void => { // Increase the default max buffer size (1 MB) const audit = exec(`${auditCommand} --json`, { maxBuffer: MAX_BUFFER_SIZE }); @@ -40,11 +45,13 @@ export function callback( // Once the stdout has completed, process the output if (audit.stderr) { - audit.stderr.on('close', () => handleFinish(jsonBuffer, auditLevel, exceptionIds, modulesToIgnore, columnsToInclude)); + audit.stderr.on('close', () => + handleFinish(jsonBuffer, auditLevel, exceptionIds, modulesToIgnore, columnsToInclude, outputJson, exceptionsReport), + ); // stderr audit.stderr.on('data', console.error); } -} +}; program.name(packageJson.name).version(packageJson.version); @@ -57,6 +64,7 @@ program .option('-p, --production', 'Skip checking the devDependencies.') .option('-r, --registry ', 'The npm registry url to use.') .option('-i, --include-columns ,,..,', 'Columns to include in report.') + .option('-j, --json', 'Output audit report in JSON format') .action((options: CommandOptions) => handleInput(options, callback)); program.parse(process.argv); diff --git a/package.json b/package.json index 9544da0..37e4707 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ }, "scripts": { "preaudit": "npm run build", - "audit": "node lib audit -x 1064843,1067245", + "audit": "node lib audit -j -x 1064843,1067245", "test": "mocha -r ts-node/register test/**/*.test.ts", "lint": "eslint .", "qc": "npm run test && npm run lint", diff --git a/src/handlers/handleFinish.ts b/src/handlers/handleFinish.ts index 3f4c6ce..e3e7739 100644 --- a/src/handlers/handleFinish.ts +++ b/src/handlers/handleFinish.ts @@ -1,5 +1,5 @@ import { AuditLevel } from 'src/types'; -import { printSecurityReport } from '../utils/print'; +import { printJsonOutput, printSecurityReport } from '../utils/print'; import { processAuditJson, handleUnusedExceptions } from '../utils/vulnerability'; /** @@ -9,6 +9,8 @@ import { processAuditJson, handleUnusedExceptions } from '../utils/vulnerability * @param {Array} exceptionIds List of vulnerability IDs to exclude * @param {Array} exceptionModules List of vulnerable modules to ignore in audit results * @param {Array} columnsToInclude List of columns to include in audit results + * @param {Boolean} outputJson Output audit report in JSON format + * @param {Array} exceptionsReport List of exceptions */ export default function handleFinish( jsonBuffer: string, @@ -16,14 +18,11 @@ export default function handleFinish( exceptionIds: string[], exceptionModules: string[], columnsToInclude: string[], + outputJson: boolean, + exceptionsReport: string[][], ): void { - const { unhandledIds, report, failed, unusedExceptionIds, unusedExceptionModules } = processAuditJson( - jsonBuffer, - auditLevel, - exceptionIds, - exceptionModules, - columnsToInclude, - ); + const result = processAuditJson(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude, outputJson); + const { unhandledIds, report, failed, unusedExceptionIds, unusedExceptionModules } = result; // If unable to process the audit JSON if (failed) { @@ -34,21 +33,31 @@ export default function handleFinish( } // Print the security report - if (report.length) { - printSecurityReport(report, columnsToInclude); - } + if (outputJson) { + printJsonOutput(result, exceptionsReport); + } else { + if (report.length) { + printSecurityReport(report, columnsToInclude); + } - // Handle unused exceptions - handleUnusedExceptions(unusedExceptionIds, unusedExceptionModules); + // Handle unused exceptions + handleUnusedExceptions(unusedExceptionIds, unusedExceptionModules); + } // Display the found unhandled vulnerabilities if (unhandledIds.length) { - console.error(`${unhandledIds.length} vulnerabilities found. Node security advisories: ${unhandledIds.join(', ')}`); + if (!outputJson) { + console.error(`${unhandledIds.length} vulnerabilities found. Node security advisories: ${unhandledIds.join(', ')}`); + } + // Exit failed process.exit(1); } else { // Happy happy, joy joy - console.info('🤝 All good!'); + if (!outputJson) { + console.info('🤝 All good!'); + } + process.exit(0); } } diff --git a/src/handlers/handleInput.ts b/src/handlers/handleInput.ts index 9219324..3123edd 100644 --- a/src/handlers/handleInput.ts +++ b/src/handlers/handleInput.ts @@ -1,15 +1,26 @@ import get from 'lodash.get'; import semver from 'semver'; import { AuditLevel, CommandOptions } from 'src/types'; +import type { ProcessedReport } from 'src/types'; import { getNpmVersion } from '../utils/npm'; import { readFile } from '../utils/file'; -import { getExceptionsIds } from '../utils/vulnerability'; +import { getProcessedExceptions } from '../utils/vulnerability'; + +export type HandleInputCallback = ( + auditCommand: string, + auditLevel: AuditLevel, + exceptionIds: string[], + modulesToIgnore: string[], + columnsToInclude: string[], + outputJson: boolean, + exceptionsReport: string[][], +) => void; /** * Get the `npm audit` flag to audit only production dependencies. * @return {String} The flag. */ -function getProductionOnlyOption() { +function getProductionOnlyOption(): string { const npmVersion = getNpmVersion(); if (semver.satisfies(npmVersion, '<=8.13.2')) { return '--production'; @@ -22,10 +33,7 @@ function getProductionOnlyOption() { * @param {Object} options User's command options or flags * @param {Function} fn The function to handle the inputs */ -export default function handleInput( - options: CommandOptions, - fn: (T1: string, T2: AuditLevel, T3: string[], T4: string[], T5: string[]) => void, -): void { +export default function handleInput(options: CommandOptions, fn: HandleInputCallback): void { // Generate NPM Audit command const auditCommand: string = [ 'npm audit', @@ -46,12 +54,13 @@ export default function handleInput( .split(',') .map((each) => each.trim()) .filter((each) => each !== ''); - const exceptionIds: string[] = getExceptionsIds(nsprc, cmdExceptions); + const outputJson: boolean = get(options, 'json', false); + const { exceptionIds, report: exceptionsReport }: ProcessedReport = getProcessedExceptions(nsprc, cmdExceptions, outputJson); const cmdModuleIgnore: string[] = get(options, 'moduleIgnore', '').split(','); const cmdIncludeColumns: string[] = get(options, 'includeColumns', '') .split(',') .map((each: string) => each.trim()) .filter((each: string) => !!each); - fn(auditCommand, auditLevel, exceptionIds, cmdModuleIgnore, cmdIncludeColumns); + fn(auditCommand, auditLevel, exceptionIds, cmdModuleIgnore, cmdIncludeColumns, outputJson, exceptionsReport); } diff --git a/src/types/general.d.ts b/src/types/general.d.ts index e4e2552..4809029 100644 --- a/src/types/general.d.ts +++ b/src/types/general.d.ts @@ -1,4 +1,5 @@ import { AuditLevel, Severity } from './level'; +import type { ExceptionReportKey, SecurityReportKey } from './table'; export interface CommandOptions { readonly exclude?: string; @@ -7,6 +8,7 @@ export interface CommandOptions { readonly level?: AuditLevel; readonly registry?: string; readonly includeColumns?: string; + readonly json?: boolean; } export interface NpmAuditJson { @@ -63,6 +65,19 @@ export interface ProcessedResult { unusedExceptionModules: string[]; } +export interface JsonOutput { + /** Whether there was a failure and the output is not accurate */ + readonly failed: boolean; + /** List of all found vulnerabilities */ + readonly vulnerabilitiesReport: Record[]; + /** List of unhandled vulnerabilities, ie those that cause the audit to fail */ + readonly unhandledVulnerabilityIds: string[]; + /** List of all exceptions */ + readonly exceptionsReport: Record[]; + /** List of unused exceptions */ + readonly unusedExceptionIds: string[]; +} + export interface ProcessedReport { readonly exceptionIds: string[]; readonly report: string[][]; diff --git a/src/types/table.d.ts b/src/types/table.d.ts index f974ea3..d8acbae 100644 --- a/src/types/table.d.ts +++ b/src/types/table.d.ts @@ -1,2 +1,8 @@ +/** Display names for table columns */ export type SecurityReportHeader = 'ID' | 'Module' | 'Title' | 'Paths' | 'Severity' | 'URL' | 'Ex.'; +/** Names for object properties */ +export type SecurityReportKey = 'id' | 'module' | 'title' | 'paths' | 'severity' | 'url' | 'isExcepted'; +/** Display names for table columns */ export type ExceptionReportHeader = 'ID' | 'Status' | 'Expiry' | 'Notes'; +/** Names for object properties */ +export type ExceptionReportKey = 'id' | 'status' | 'expiry' | 'notes'; diff --git a/src/utils/color.ts b/src/utils/color.ts index 6c3f9ed..e5a0cda 100644 --- a/src/utils/color.ts +++ b/src/utils/color.ts @@ -46,10 +46,11 @@ const COLORS = { * @param {String} message Message * @param {String} fgColor Foreground color * @param {String} bgColor Background color + * @param {Boolean} condition Condition to color the message, when false it will return the message without color * @return {String} Message */ -export function color(message: string, fgColor?: Color, bgColor?: Color): string { - if ('NO_COLOR' in process.env) { +export function color(message: string, fgColor?: Color, bgColor?: Color, condition = true): string { + if ('NO_COLOR' in process.env || !condition) { return message; } diff --git a/src/utils/print.ts b/src/utils/print.ts index 9f433ac..89ed379 100644 --- a/src/utils/print.ts +++ b/src/utils/print.ts @@ -1,10 +1,40 @@ +/* eslint-disable quote-props */ import get from 'lodash.get'; import { table, TableUserConfig } from 'table'; -import { SecurityReportHeader, ExceptionReportHeader } from 'src/types'; +import type { + SecurityReportHeader, + ExceptionReportHeader, + ProcessedResult, + JsonOutput, + SecurityReportKey, + ExceptionReportKey, +} from 'src/types'; const SECURITY_REPORT_HEADER: SecurityReportHeader[] = ['ID', 'Module', 'Title', 'Paths', 'Severity', 'URL', 'Ex.']; const EXCEPTION_REPORT_HEADER: ExceptionReportHeader[] = ['ID', 'Status', 'Expiry', 'Notes']; +const SECURITY_REPORT_HEADER_TO_OBJECT_KEY_MAP: Record = { + ID: 'id', + Module: 'module', + Title: 'title', + Paths: 'paths', + Severity: 'severity', + URL: 'url', + 'Ex.': 'isExcepted', +}; + +const EXCEPTION_REPORT_HEADER_TO_OBJECT_KEY_MAP: Record = { + ID: 'id', + Status: 'status', + Expiry: 'expiry', + Notes: 'notes', +}; + +const SECURITY_REPORT_KEYS: SecurityReportKey[] = SECURITY_REPORT_HEADER.map((header) => SECURITY_REPORT_HEADER_TO_OBJECT_KEY_MAP[header]); +const EXCEPTION_REPORT_KEYS: ExceptionReportKey[] = EXCEPTION_REPORT_HEADER.map( + (header) => EXCEPTION_REPORT_HEADER_TO_OBJECT_KEY_MAP[header], +); + // TODO: Add unit tests /** * Get the column width size for the table @@ -66,10 +96,10 @@ export function printSecurityReport(data: string[][], columnsToInclude: string[] /** * Print the exception report in a table format - * @param {Array} data Array of arrays - * @return {undefined} Returns void + * @param {Array} exceptionsReport Array of arrays + * @return {undefined} Returns void */ -export function printExceptionReport(data: string[][]): void { +export function printExceptionReport(exceptionsReport: string[][]): void { const configs: TableUserConfig = { singleLine: true, header: { @@ -78,5 +108,39 @@ export function printExceptionReport(data: string[][]): void { }, }; - console.info(table([EXCEPTION_REPORT_HEADER, ...data], configs)); + console.info(table([EXCEPTION_REPORT_HEADER, ...exceptionsReport], configs)); +} + +/** + * Print the JSON output + * @param {Object} result The processed result + * @param {Array} exceptionsReport The exceptions report + * @return {undefined} Returns void + */ +export function printJsonOutput(result: ProcessedResult, exceptionsReport: string[][]): void { + const jsonOutput: JsonOutput = { + failed: result.failed ?? false, + unhandledVulnerabilityIds: result.unhandledIds.filter(Boolean), + vulnerabilitiesReport: convertReportTuplesToObjects(result.report, SECURITY_REPORT_KEYS), + exceptionsReport: convertReportTuplesToObjects(exceptionsReport, EXCEPTION_REPORT_KEYS), + unusedExceptionIds: result.unusedExceptionIds.filter(Boolean), + }; + + console.info(JSON.stringify(jsonOutput, null, 2)); +} + +/** + * Convert a given report tuple to an object with the given headers + * @param {Array} report Report where each row is a tuple + * @param {Array} elementKeyNames Array of object key names to use for each tuple element + * @return {Array} Report where each row is an object + */ +function convertReportTuplesToObjects(report: string[][], elementKeyNames: THeader[]): Record[] { + return report.map((rowTuple) => + rowTuple.reduce((rowObj, colValue, i) => { + const header = elementKeyNames[i]; + rowObj[header] = colValue; + return rowObj; + }, {} as Record), + ); } diff --git a/src/utils/vulnerability.ts b/src/utils/vulnerability.ts index 1feddf7..86b7df8 100644 --- a/src/utils/vulnerability.ts +++ b/src/utils/vulnerability.ts @@ -17,6 +17,7 @@ import { AuditLevel, AuditNumber, } from 'src/types'; +import type { Color } from 'src/types'; const MAX_PATHS_SIZE = 5; @@ -115,6 +116,7 @@ export function validateV7Vulnerability( * @param {Array} exceptionIds Exception IDs (ID to be ignored) * @param {Array} exceptionModules Exception modules (modules to be ignored) * @param {Array} columnsToInclude List of columns to include in audit results + * @param {Boolean} outputJson Whether the output is in JSON format * @return {Object} Processed vulnerabilities details */ export function processAuditJson( @@ -123,6 +125,7 @@ export function processAuditJson( exceptionIds: string[] = [], exceptionModules: string[] = [], columnsToInclude: string[] = [], + outputJson = false, ): ProcessedResult { if (!isJsonString(jsonBuffer)) { return { @@ -174,9 +177,9 @@ export function processAuditJson( { key: 'Ex.', value: isExcepted ? 'y' : 'n' }, ] .filter(({ key }) => (columnsToInclude.length ? columnsToInclude.includes(key) : true)) - .map(({ key, value }) => - color(value, isExcepted ? '' : 'yellow', key === 'Severity' ? getSeverityBgColor(cur.severity) : undefined), - ); + .map(({ key, value }) => { + return color(value, isExcepted ? '' : 'yellow', key === 'Severity' ? getSeverityBgColor(cur.severity) : undefined, !outputJson); + }); // Record this vulnerability into the report, and highlight it using yellow color if it's new acc.report.push(rowData); @@ -242,7 +245,9 @@ export function processAuditJson( { key: 'Ex.', value: isExcepted ? 'y' : 'n' }, ] .filter(({ key }) => (columnsToInclude.length ? columnsToInclude.includes(key) : true)) - .map(({ key, value, bgColor }) => color(value, isExcepted ? '' : 'yellow', key === 'Severity' ? bgColor : undefined)); + .map(({ key, value, bgColor }) => + color(value, isExcepted ? '' : 'yellow', key === 'Severity' ? bgColor : undefined, !outputJson), + ); // Record this vulnerability into the report, and highlight it using yellow color if it's new acc.report.push(rowData); @@ -282,39 +287,56 @@ export function processAuditJson( } /** - * Process all exceptions and return a list of exception IDs + * Process all exceptions and return a list of exception IDs and the exception report * @param {Object | Boolean} nsprc File content from `.nsprc` * @param {Array} cmdExceptions Exceptions passed in via command line + * @param {Boolean} outputJson Whether the output is in JSON format * @return {Array} List of found vulnerabilities */ -export function getExceptionsIds(nsprc?: NsprcFile | boolean, cmdExceptions: string[] = []): string[] { +export function getProcessedExceptions(nsprc: NsprcFile | boolean, cmdExceptions: string[], outputJson: boolean): ProcessedReport { // If file does not exists if (!nsprc || typeof nsprc !== 'object') { // If there are exceptions passed in from command line if (cmdExceptions.length) { - // Display simple info - console.info(`Exception IDs: ${cmdExceptions.join(', ')}`); - return cmdExceptions; + if (!outputJson) { + // Display simple info + console.info(`Exception IDs: ${cmdExceptions.join(', ')}`); + } + return processExceptions({}, cmdExceptions, outputJson); } - return []; + return { exceptionIds: [], report: [] }; } // Process the content of the file along with the command line exceptions - const { exceptionIds, report } = processExceptions(nsprc, cmdExceptions); + const processedExceptions = processExceptions(nsprc, cmdExceptions, outputJson); + + if (!outputJson) { + printExceptionReport(processedExceptions.report); + } - printExceptionReport(report); + return processedExceptions; +} - return exceptionIds; +/** + * Process all exceptions and return a list of exception IDs + * @param {Object | Boolean} nsprc File content from `.nsprc` + * @param {Array} cmdExceptions Exceptions passed in via command line + * @param {Boolean} outputJson Whether the output is in JSON format + * @return {Array} List of found vulnerabilities + */ +export function getExceptionsIds(nsprc: NsprcFile | boolean, cmdExceptions: string[], outputJson: boolean): string[] { + return getProcessedExceptions(nsprc, cmdExceptions, outputJson).exceptionIds; } /** * Filter the given list in the `.nsprc` file for valid exceptions * @param {Object} nsprc The nsprc file content, contains exception info * @param {Array} cmdExceptions Exceptions passed in via command line + * @param {Boolean} outputJson Whether the output is in JSON format * @return {Object} Processed vulnerabilities details */ -export function processExceptions(nsprc: NsprcFile, cmdExceptions: string[] = []): ProcessedReport { +export function processExceptions(nsprc: NsprcFile, cmdExceptions: string[], outputJson: boolean): ProcessedReport { return Object.entries(nsprc).reduce( (acc: ProcessedReport, [id, details]: [string, string | NsprcConfigs]) => { const isActive = Boolean(get(details, 'active', true)); // default to true @@ -322,22 +344,22 @@ export function processExceptions(nsprc: NsprcFile, cmdExceptions: string[] = [] const { valid, expired, years } = analyzeExpiry(get(details, 'expiry')); // Color the status accordingly - let status = color('active', 'green'); + let status = color('active', 'green', undefined, !outputJson); if (expired) { - status = color('expired', 'red'); + status = color('expired', 'red', undefined, !outputJson); } else if (!valid) { - status = color('invalid', 'red'); + status = color('invalid', 'red', undefined, !outputJson); } else if (!isActive) { - status = color('inactive', 'yellow'); + status = color('inactive', 'yellow', undefined, !outputJson); } // Color the date accordingly let expiryDate = get(details, 'expiry') ? new Date(get(details, 'expiry')).toUTCString() : ''; // If it was expired for more than 5 years ago, warn by coloring the date in red if (years && years <= -5) { - expiryDate = color(expiryDate, 'red'); + expiryDate = color(expiryDate, 'red', undefined, !outputJson); } else if (years && years <= -1) { - expiryDate = color(expiryDate, 'yellow'); + expiryDate = color(expiryDate, 'yellow', undefined, !outputJson); } acc.report.push([id, status, expiryDate, notes]); @@ -350,7 +372,7 @@ export function processExceptions(nsprc: NsprcFile, cmdExceptions: string[] = [] }, { exceptionIds: cmdExceptions, - report: cmdExceptions.map((id) => [String(id), color('active', 'green'), '', '']), + report: cmdExceptions.map((id) => [String(id), color('active', 'green', undefined, !outputJson), '', '']), }, ); } diff --git a/test/handlers/handleFinish.test.ts b/test/handlers/handleFinish.test.ts index 2f306be..ee87cb0 100644 --- a/test/handlers/handleFinish.test.ts +++ b/test/handlers/handleFinish.test.ts @@ -19,7 +19,7 @@ describe('Events handling', () => { expect(processStub.called).to.equal(false); expect(consoleStub.called).to.equal(false); - handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude); + handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude, false, []); expect(processStub.called).to.equal(true); expect(processStub.calledWith(1)).to.equal(true); @@ -41,7 +41,7 @@ describe('Events handling', () => { const columnsToInclude: string[] = []; expect(consoleStub.called).to.equal(false); - handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude); + handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude, false, []); expect(processStub.called).to.equal(true); expect(processStub.calledWith(0)).to.equal(true); @@ -63,7 +63,7 @@ describe('Events handling', () => { const columnsToInclude: string[] = []; expect(consoleStub.called).to.equal(false); - handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude); + handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude, false, []); expect(processStub.called).to.equal(true); expect(processStub.calledWith(0)).to.equal(true); @@ -89,7 +89,7 @@ describe('Events handling', () => { expect(consoleErrorStub.called).to.equal(false); expect(consoleInfoStub.called).to.equal(false); - handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude); + handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude, false, []); expect(processStub.called).to.equal(true); expect(consoleErrorStub.called).to.equal(true); @@ -119,7 +119,7 @@ describe('Events handling', () => { expect(consoleWarnStub.called).to.equal(false); expect(consoleInfoStub.called).to.equal(false); - handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude); + handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude, false, []); expect(processStub.called).to.equal(true); expect(processStub.calledWith(1)).to.equal(true); @@ -141,7 +141,7 @@ describe('Events handling', () => { // Message for multiple unused exceptions exceptionIds = ['975', '976', '985', '1084', '1179', '1213', '1500', '1523', '1555', '2001', '2002']; exceptionModules = ['fakeModule1']; - handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude); + handleFinish(jsonBuffer, auditLevel, exceptionIds, exceptionModules, columnsToInclude, false, []); message = [ '2 of the excluded vulnerabilities did not match any of the found vulnerabilities: 2001, 2002.', 'They can be removed from the .nsprc file or --exclude -x flags.', @@ -155,4 +155,6 @@ describe('Events handling', () => { consoleWarnStub.restore(); consoleInfoStub.restore(); }); + + // todo add json output tests }); diff --git a/test/utils/print.test.ts b/test/utils/print.test.ts index 18d5f5e..de37b20 100644 --- a/test/utils/print.test.ts +++ b/test/utils/print.test.ts @@ -16,6 +16,8 @@ describe('Print utils', () => { it('exception table visual', () => { printExceptionReport(EXCEPTION_TABLE_DATA); }); + + // todo add json output tests }); export {}; diff --git a/test/utils/vulnerability.test.ts b/test/utils/vulnerability.test.ts index a6cc2a4..656d81e 100644 --- a/test/utils/vulnerability.test.ts +++ b/test/utils/vulnerability.test.ts @@ -131,7 +131,7 @@ describe('Vulnerability utils', () => { const consoleStub = sinon.stub(console, 'info'); const cmdExceptions = ['1165', '1890']; expect(consoleStub.called).to.equal(false); - const result = getExceptionsIds(false, cmdExceptions); + const result = getExceptionsIds(false, cmdExceptions, false); expect(result).to.have.length(2).and.deep.equal(['1165', '1890']); expect(consoleStub.called).to.equal(true); expect(consoleStub.calledWith('Exception IDs: 1165, 1890')).to.equal(true); @@ -142,7 +142,7 @@ describe('Vulnerability utils', () => { const consoleStub = sinon.stub(console, 'info'); const cmdExceptions = ['1165', '1890']; expect(consoleStub.called).to.equal(false); - const result = getExceptionsIds(NSPRC, cmdExceptions); + const result = getExceptionsIds(NSPRC, cmdExceptions, false); expect(result) .to.have.length(9) .and.deep.equal(['1165', '1890', '985', '1213', '2000', '2001', '2100', 'CWE-126', 'GHSA-ww39-953v-wcq6']); @@ -154,7 +154,7 @@ describe('Vulnerability utils', () => { describe('#processExceptions', () => { it('should be able to process exceptions correctly', () => { const cmdExceptions = ['1165', '1890']; - const result = processExceptions(NSPRC, cmdExceptions); + const result = processExceptions(NSPRC, cmdExceptions, false); expect(result).to.have.property('exceptionIds'); expect(result.exceptionIds) @@ -165,7 +165,7 @@ describe('Vulnerability utils', () => { }); it('should be able to filter active exceptions and label correctly', () => { - const result = processExceptions(NSPRC); + const result = processExceptions(NSPRC, [], false); expect(result).to.have.property('exceptionIds').and.to.have.length(7); expect(result).to.have.property('report'); @@ -176,7 +176,7 @@ describe('Vulnerability utils', () => { }); it('should be able to filter inactive exceptions and label correctly', () => { - const result = processExceptions(NSPRC); + const result = processExceptions(NSPRC, [], false); expect(result).to.have.property('exceptionIds').and.to.have.length(7); expect(result).to.have.property('report'); @@ -188,7 +188,7 @@ describe('Vulnerability utils', () => { it('should be able to filter expired exceptions and label correctly', () => { const dateStub = sinon.stub(Date, 'now').returns(new Date(Date.UTC(2021, 6, 1)).valueOf()); - const result = processExceptions(NSPRC); + const result = processExceptions(NSPRC, [], false); expect(result).to.have.property('exceptionIds').and.to.have.length(7); expect(result).to.have.property('report').and.to.have.length(14); const activeExceptionIds = result.report @@ -542,6 +542,8 @@ describe('Vulnerability utils', () => { consoleStub.restore(); }); }); + + // todo add json output tests }); export {};