UNPKG

auditjs

Version:

Audit dependencies to identify known vulnerabilities and maintenance problems

258 lines 15 kB
"use strict"; /* * Copyright 2019-Present Sonatype Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Application = void 0; const figlet_1 = require("figlet"); const IqRequestService_1 = require("../Services/IqRequestService"); const NpmList_1 = require("../Munchers/NpmList"); const OssIndexRequestService_1 = require("../Services/OssIndexRequestService"); const AuditIQServer_1 = require("../Audit/AuditIQServer"); const AuditOSSIndex_1 = require("../Audit/AuditOSSIndex"); const OssIndexServerResult_1 = require("../Types/OssIndexServerResult"); const ReportStatus_1 = require("../Types/ReportStatus"); const Bower_1 = require("../Munchers/Bower"); const Logger_1 = require("./Logger/Logger"); const Spinner_1 = require("./Spinner/Spinner"); const VulnerabilityExcluder_1 = require("../Whitelist/VulnerabilityExcluder"); const IqServerConfig_1 = require("../Config/IqServerConfig"); const OssIndexServerConfig_1 = require("../Config/OssIndexServerConfig"); const VisualHelper_1 = require("../Visual/VisualHelper"); const pj = require('../../package.json'); class Application { constructor(devDependency = false, silent = false, artie = false, allen = false, scanBower = false) { this.devDependency = devDependency; this.silent = silent; this.artie = artie; this.allen = allen; this.scanBower = scanBower; this.results = []; this.sbom = ''; const npmList = new NpmList_1.NpmList(devDependency); const bower = new Bower_1.Bower(devDependency); this.printHeader(); this.spinner = new Spinner_1.Spinner(silent); (0, Logger_1.createAppLogger)(); if (npmList.isValid() && !this.scanBower) { (0, Logger_1.logMessage)('Setting Muncher to npm list', Logger_1.DEBUG); this.muncher = npmList; } else if (bower.isValid()) { (0, Logger_1.logMessage)('Setting Muncher to bower', Logger_1.DEBUG); this.muncher = bower; } else { (0, Logger_1.logMessage)('Failed project directory validation. Are you in a (built) node, yarn, or bower project directory?', 'error'); throw new Error('Could not instantiate muncher'); } } startApplication(args) { return __awaiter(this, void 0, void 0, function* () { if (args._[0] == 'iq') { (0, Logger_1.logMessage)('Attempting to start application', Logger_1.DEBUG); (0, Logger_1.logMessage)('Getting coordinates for Sonatype IQ', Logger_1.DEBUG); this.spinner.maybeCreateMessageForSpinner('Getting coordinates for Sonatype IQ'); yield this.populateCoordinatesForIQ(); (0, Logger_1.logMessage)(`Coordinates obtained`, Logger_1.DEBUG, this.sbom); this.spinner.maybeSucceed(); (0, Logger_1.logMessage)(`Auditing application`, Logger_1.DEBUG, args.application); this.spinner.maybeCreateMessageForSpinner('Auditing your application with Sonatype IQ'); yield this.auditWithIQ(args); } else if (args._[0] == 'ossi') { (0, Logger_1.logMessage)('Attempting to start application', Logger_1.DEBUG); (0, Logger_1.logMessage)('Getting coordinates for Sonatype OSS Index', Logger_1.DEBUG); this.spinner.maybeCreateMessageForSpinner('Getting coordinates for Sonatype OSS Index'); yield this.populateCoordinates(); (0, Logger_1.logMessage)(`Coordinates obtained`, Logger_1.DEBUG, this.results); this.spinner.maybeSucceed(); (0, Logger_1.logMessage)('Auditing your application with Sonatype OSS Index', Logger_1.DEBUG); this.spinner.maybeCreateMessageForSpinner('Auditing your application with Sonatype OSS Index'); yield this.auditWithOSSIndex(args); } else if (args._[0] == 'sbom') { yield this.populateCoordinatesForIQ(); console.log(this.sbom); } else { (0, Logger_1.shutDownLoggerAndExit)(1); } }); } printHeader() { if (this.silent) { return; } else if (this.artie) { this.doPrintHeader('ArtieJS', 'Ghost'); } else if (this.allen) { this.doPrintHeader('AllenJS', 'Ghost'); } else { this.doPrintHeader(); } } doPrintHeader(title = 'AuditJS', font = '3D-ASCII') { console.log((0, figlet_1.textSync)(title, { font: font, horizontalLayout: 'fitted' })); console.log((0, figlet_1.textSync)('By Sonatype & Friends', { font: 'Pepper' })); (0, VisualHelper_1.visuallySeperateText)(false, [`${title} version: ${pj.version}`]); } populateCoordinates() { return __awaiter(this, void 0, void 0, function* () { try { (0, Logger_1.logMessage)('Trying to get dependencies from Muncher', Logger_1.DEBUG); this.results = yield this.muncher.getDepList(); (0, Logger_1.logMessage)('Successfully got dependencies from Muncher', Logger_1.DEBUG); } catch (e) { (0, Logger_1.logMessage)(`An error was encountered while gathering your dependencies.`, Logger_1.ERROR, { title: e.message, stack: e.stack, }); (0, Logger_1.shutDownLoggerAndExit)(1); } }); } populateCoordinatesForIQ() { return __awaiter(this, void 0, void 0, function* () { try { (0, Logger_1.logMessage)('Trying to get sbom from cyclonedx/bom', Logger_1.DEBUG); this.sbom = yield this.muncher.getSbomFromCommand(); (0, Logger_1.logMessage)('Successfully got sbom from cyclonedx/bom', Logger_1.DEBUG); } catch (e) { (0, Logger_1.logMessage)(`An error was encountered while gathering your dependencies into an SBOM`, Logger_1.ERROR, { title: e.message, stack: e.stack, }); (0, Logger_1.shutDownLoggerAndExit)(1); } }); } auditWithOSSIndex(args) { return __awaiter(this, void 0, void 0, function* () { (0, Logger_1.logMessage)('Instantiating OSS Index Request Service', Logger_1.DEBUG); const requestService = this.getOssIndexRequestService(args); this.spinner.maybeSucceed(); (0, Logger_1.logMessage)('Submitting coordinates to Sonatype OSS Index', Logger_1.DEBUG); this.spinner.maybeCreateMessageForSpinner('Submitting coordinates to Sonatype OSS Index'); const format = this.muncher instanceof Bower_1.Bower ? 'bower' : 'npm'; (0, Logger_1.logMessage)('Format to query OSS Index picked', Logger_1.DEBUG, { format: format }); try { (0, Logger_1.logMessage)('Attempting to query OSS Index or use Cache', Logger_1.DEBUG); const res = yield requestService.callOSSIndexOrGetFromCache(this.results, format); (0, Logger_1.logMessage)('Success from OSS Index', Logger_1.DEBUG, res); this.spinner.maybeSucceed(); this.spinner.maybeCreateMessageForSpinner('Reticulating splines'); (0, Logger_1.logMessage)('Turning response into Array<OssIndexServerResult>', Logger_1.DEBUG); let ossIndexResults = res.map((y) => { return new OssIndexServerResult_1.OssIndexServerResult(y); }); (0, Logger_1.logMessage)('Response morphed into Array<OssIndexServerResult>', Logger_1.DEBUG, { ossIndexServerResults: ossIndexResults, }); this.spinner.maybeSucceed(); this.spinner.maybeCreateMessageForSpinner('Removing whitelisted vulnerabilities'); (0, Logger_1.logMessage)('Response being ran against whitelist', Logger_1.DEBUG, { ossIndexServerResults: ossIndexResults }); ossIndexResults = yield (0, VulnerabilityExcluder_1.filterVulnerabilities)(ossIndexResults, args.whitelist); (0, Logger_1.logMessage)('Response has been whitelisted', Logger_1.DEBUG, { ossIndexServerResults: ossIndexResults }); this.spinner.maybeSucceed(); this.spinner.maybeCreateMessageForSpinner('Auditing your results from Sonatype OSS Index'); (0, Logger_1.logMessage)('Instantiating OSS Index Request Service, with quiet option', Logger_1.DEBUG, { quiet: args.quiet }); const auditOSSIndex = new AuditOSSIndex_1.AuditOSSIndex(args.quiet ? true : false, args.json ? true : false, args.xml ? true : false); this.spinner.maybeStop(); (0, Logger_1.logMessage)('Attempting to audit results', Logger_1.DEBUG); const failed = auditOSSIndex.auditResults(ossIndexResults); (0, Logger_1.logMessage)('Results audited', Logger_1.DEBUG, { failureCode: failed }); failed ? (0, Logger_1.shutDownLoggerAndExit)(1) : (0, Logger_1.shutDownLoggerAndExit)(0); } catch (e) { this.spinner.maybeStop(); (0, Logger_1.logMessage)('There was an error auditing with Sonatype OSS Index', Logger_1.ERROR, { title: e.message, stack: e.stack }); (0, Logger_1.shutDownLoggerAndExit)(1); } }); } auditWithIQ(args) { return __awaiter(this, void 0, void 0, function* () { try { this.spinner.maybeSucceed(); this.spinner.maybeCreateMessageForSpinner('Authenticating with Sonatype IQ'); (0, Logger_1.logMessage)('Attempting to connect to Sonatype IQ', Logger_1.DEBUG, args.application); const requestService = this.getIqRequestService(args); this.spinner.maybeSucceed(); this.spinner.maybeCreateMessageForSpinner('Submitting your dependencies'); (0, Logger_1.logMessage)('Submitting SBOM to Sonatype IQ', Logger_1.DEBUG, this.sbom); const resultUrl = yield requestService.submitToThirdPartyAPI(this.sbom); this.spinner.maybeSucceed(); this.spinner.maybeCreateMessageForSpinner('Checking for results (this could take a minute)'); (0, Logger_1.logMessage)('Polling IQ for report results', Logger_1.DEBUG, resultUrl); requestService.asyncPollForResults(`${resultUrl}`, (e) => { this.spinner.maybeFail(); (0, Logger_1.logMessage)('There was an issue auditing your application!', Logger_1.ERROR, { title: e.message, stack: e.stack }); (0, Logger_1.shutDownLoggerAndExit)(1); }, (x) => { this.spinner.maybeSucceed(); this.spinner.maybeCreateMessageForSpinner('Auditing your results'); const results = Object.assign(new ReportStatus_1.ReportStatus(), x); (0, Logger_1.logMessage)('Sonatype IQ results obtained!', Logger_1.DEBUG, results); results.reportHtmlUrl = new URL(results.reportHtmlUrl, requestService.host).href; const auditResults = new AuditIQServer_1.AuditIQServer(); this.spinner.maybeStop(); (0, Logger_1.logMessage)('Auditing results', Logger_1.DEBUG, results); const failure = auditResults.auditThirdPartyResults(results); (0, Logger_1.logMessage)('Audit finished', Logger_1.DEBUG, { failure: failure }); failure ? (0, Logger_1.shutDownLoggerAndExit)(1) : (0, Logger_1.shutDownLoggerAndExit)(0); }); } catch (e) { this.spinner.maybeFail(); (0, Logger_1.logMessage)('There was an issue auditing your application!', Logger_1.ERROR, { title: e.message, stack: e.stack }); (0, Logger_1.shutDownLoggerAndExit)(1); } }); } getOssIndexRequestService(args) { let config; try { config = new OssIndexServerConfig_1.OssIndexServerConfig(); config.getConfigFromFile(); } catch (e) { // Ignore config load failure } return new OssIndexRequestService_1.OssIndexRequestService((args === null || args === void 0 ? void 0 : args.user) || (config === null || config === void 0 ? void 0 : config.getUsername()), (args === null || args === void 0 ? void 0 : args.password) || (config === null || config === void 0 ? void 0 : config.getToken()), (args === null || args === void 0 ? void 0 : args.cache) || (config === null || config === void 0 ? void 0 : config.getCacheLocation())); } getIqRequestService(args) { const config = new IqServerConfig_1.IqServerConfig(); //config.getConfigFromFile(); if (!config.exists() && !(args.user && args.password && args.server)) throw new Error('No config file is defined and you are missing one of the -h (host), -u (user), or -p (password) parameters.'); return new IqRequestService_1.IqRequestService(args.user !== undefined ? args.user : config.getUsername(), args.password !== undefined ? args.password : config.getToken(), args.server !== undefined ? args.server : config.getHost(), args.application, args.stage, args.timeout, args.insecure); } } exports.Application = Application; //# sourceMappingURL=Application.js.map