UNPKG

node-version-audit

Version:

Audit your Node version for known CVEs and patches

180 lines (170 loc) • 6.19 kB
const { InvalidArgumentException, InvalidVersionException, StaleRulesException, InvalidRuntimeException, } = require('./Exceptions'); const { EOL } = require('os'); const util = require('util'); const { NodeVersionAudit } = require('./NodeVersionAudit'); const { Args } = require('./Args'); const { SUPPORT_TYPE } = require('./SupportSchedule'); const { Logger } = require('./Logger'); const EXIT_CODES = { FAIL_SECURITY: 10, FAIL_SUPPORT: 20, FAIL_PATCH: 30, FAIL_MINOR: 40, FAIL_LATEST: 50, FAIL_STALE: 100, INVALID_ARG: 110, INVALID_VERSION: 120, INVALID_RUNTIME: 130, }; /** * @param {string[]} argv * @constructor */ function Cli(argv) { try { this.args = Args.parseArgs(argv); Logger.setVerbosity(this.args.getVerbosity()); } catch (e) { if (e instanceof InvalidArgumentException) { Cli.showHelp(); Logger.error(e); process.exit(EXIT_CODES.INVALID_ARG); } throw e; } } /** * @return {Promise<AuditResults>} */ Cli.prototype.run = async function () { if (this.args[Args.OPTIONS.HELP]) { Cli.showHelp(); return process.exit(0); } let app; try { app = new NodeVersionAudit(this.args[Args.OPTIONS.NODE_VERSION], !this.args[Args.OPTIONS.NO_UPDATE]); } catch (e) { if (e instanceof InvalidVersionException) { Logger.error(e); Cli.showHelp(); return process.exit(EXIT_CODES.INVALID_VERSION); } if (e instanceof InvalidRuntimeException) { Logger.error(e); return process.exit(EXIT_CODES.INVALID_RUNTIME); } throw e; } if (this.args[Args.OPTIONS.FULL_UPDATE]) { /** * PLEASE DO NOT USE THIS. This function is intended to only be used internally for updating * project rules in github, which can then be accessed by ALL instances of Node Version Audit. * Running it locally puts unnecessary load on the source servers and cannot be re-used by others. * * The github hosted rules are setup on a cron schedule to update regularly. * Running it directly will not provide you with any new information and will only * waste time and server resources. */ await app.fullRulesUpdate(); } try { const auditDetails = await app.getAllAuditResults(); console.log(JSON.stringify(auditDetails, null, 4)); this.setExitCode(auditDetails); return auditDetails; } catch (e) { if (e instanceof StaleRulesException) { Logger.error('Rules are stale: ', e); return process.exit(EXIT_CODES.FAIL_STALE); } Logger.error(e); } }; /** * @param {AuditResults} auditResults */ Cli.prototype.setExitCode = function (auditResults) { if (this.args[Args.OPTIONS.FAIL_SECURITY] && (auditResults.hasVulnerabilities() || !auditResults.hasSupport())) { process.exitCode = EXIT_CODES.FAIL_SECURITY; } else if ( this.args[Args.OPTIONS.FAIL_SUPPORT] && (!auditResults.hasSupport() || ![SUPPORT_TYPE.CURRENT, SUPPORT_TYPE.ACTIVE].includes(auditResults.supportType)) ) { process.exitCode = EXIT_CODES.FAIL_SUPPORT; } else if (this.args[Args.OPTIONS.FAIL_LATEST] && !auditResults.isLatestVersion()) { process.exitCode = EXIT_CODES.FAIL_LATEST; } else if (this.args[Args.OPTIONS.FAIL_MINOR] && !auditResults.isLatestMinorVersion()) { process.exitCode = EXIT_CODES.FAIL_MINOR; } else if (this.args[Args.OPTIONS.FAIL_PATCH] && !auditResults.isLatestPatchVersion()) { process.exitCode = EXIT_CODES.FAIL_PATCH; } }; Cli.showHelp = function () { const usageMask = `\t\t\t\t[--%s] [--%s]${EOL}`; const argsMask = `--%s\t\t\t%s${EOL}`; const argsErrorCodeMask = `--%s\t\t\tgenerate a %s %s${EOL}`; let out = util.format(`%s${EOL}`, 'Node Version Audit'); out += util.format( `%s\t%s${EOL}`, 'usage: node-version-audit', `[--help] [--${Args.OPTIONS.NODE_VERSION}=NODE_VERSION]`, ); out += util.format(usageMask, Args.OPTIONS.FAIL_SECURITY, Args.OPTIONS.FAIL_SUPPORT); out += util.format(usageMask, Args.OPTIONS.FAIL_PATCH, Args.OPTIONS.FAIL_LATEST); out += util.format(usageMask, Args.OPTIONS.NO_UPDATE, 'silent'); out += util.format(`\t\t\t\t[--%s]${EOL}`, 'v'); out += util.format(`%s${EOL}`, 'optional arguments:'); out += util.format(argsMask, Args.OPTIONS.HELP, '\tshow this help message and exit.'); out += util.format( argsMask, Args.OPTIONS.NODE_VERSION, 'set the Node Version to run against. Defaults to the runtime version. This is required when running with docker.', ); out += util.format( argsErrorCodeMask, Args.OPTIONS.FAIL_SECURITY, EXIT_CODES.FAIL_SECURITY, 'exit code if any CVEs are found, or security support has ended.', ); out += util.format( argsErrorCodeMask, Args.OPTIONS.FAIL_SUPPORT, EXIT_CODES.FAIL_SUPPORT, 'exit code if the version of Node no longer gets active (bug) support.', ); out += util.format( argsErrorCodeMask, Args.OPTIONS.FAIL_PATCH, EXIT_CODES.FAIL_PATCH, 'exit code if there is a newer patch-level release.', ); out += util.format( argsErrorCodeMask, Args.OPTIONS.FAIL_MINOR, EXIT_CODES.FAIL_MINOR, 'exit code if there is a newer minor-level release.', ); out += util.format( argsErrorCodeMask, Args.OPTIONS.FAIL_LATEST, EXIT_CODES.FAIL_LATEST, 'exit code if there is a newer release.', ); out += util.format(argsMask, Args.OPTIONS.NO_UPDATE, 'do not download the latest rules. NOT RECOMMENDED!'); out += util.format(argsMask, 'silent', 'do not write any error messages to STDERR.'); out += util.format( argsMask, 'v', '\tSet verbosity. v=warnings, vv=info, vvv=debug. Default is error. All logging writes to STDERR.', ); console.info(out); }; module.exports = { Cli, };