auditjs
Version:
Audit dependencies to identify known vulnerabilities and maintenance problems
258 lines • 15 kB
JavaScript
"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