JezK
Edit File: audit.js
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; exports.hasWrapper = hasWrapper; exports.run = run; exports.setFlags = setFlags; function _regenerator() { var data = _interopRequireDefault(require("@babel/runtime/regenerator")); _regenerator = function _regenerator() { return data; }; return data; } function _toConsumableArray2() { var data = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); _toConsumableArray2 = function _toConsumableArray2() { return data; }; return data; } function _classCallCheck2() { var data = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); _classCallCheck2 = function _classCallCheck2() { return data; }; return data; } function _createClass2() { var data = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); _createClass2 = function _createClass2() { return data; }; return data; } function _defineProperty2() { var data = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); _defineProperty2 = function _defineProperty2() { return data; }; return data; } function _asyncToGenerator2() { var data = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); _asyncToGenerator2 = function _asyncToGenerator2() { return data; }; return data; } function _promise() { var data = require("../../util/promise.js"); _promise = function _promise() { return data; }; return data; } function _hoistedTreeBuilder() { var data = require("../../hoisted-tree-builder"); _hoistedTreeBuilder = function _hoistedTreeBuilder() { return data; }; return data; } function _getTransitiveDevDependencies() { var data = require("../../util/get-transitive-dev-dependencies"); _getTransitiveDevDependencies = function _getTransitiveDevDependencies() { return data; }; return data; } function _install() { var data = require("./install.js"); _install = function _install() { return data; }; return data; } function _lockfile() { var data = _interopRequireDefault(require("../../lockfile")); _lockfile = function _lockfile() { return data; }; return data; } function _constants() { var data = require("../../constants"); _constants = function _constants() { return data; }; return data; } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } var zlib = require('zlib'); var gzip = (0, _promise().promisify)(zlib.gzip); function setFlags(commander) { commander.description('Checks for known security issues with the installed packages.'); commander.option('--summary', 'Only print the summary.'); commander.option('--groups <group_name> [<group_name> ...]', "Only audit dependencies from listed groups. Default: ".concat(_constants().OWNED_DEPENDENCY_TYPES.join(', ')), function (groups) { return groups.split(' '); }, _constants().OWNED_DEPENDENCY_TYPES); commander.option('--level <severity>', "Only print advisories with severity greater than or equal to one of the following: info|low|moderate|high|critical. Default: info", 'info'); } function hasWrapper(commander, args) { return true; } function run(_x, _x2, _x3, _x4, _x5) { return _run.apply(this, arguments); } function _run() { _run = (0, _asyncToGenerator2()["default"])( /*#__PURE__*/_regenerator()["default"].mark(function _callee3(config, reporter, commander, flags, args) { var DEFAULT_LOG_LEVEL, audit, lockfile, install, _yield$install$fetchR, manifest, requests, patterns, workspaceLayout, vulnerabilities, EXIT_INFO, EXIT_LOW, EXIT_MODERATE, EXIT_HIGH, EXIT_CRITICAL, exitCode; return _regenerator()["default"].wrap(function _callee3$(_context3) { while (1) switch (_context3.prev = _context3.next) { case 0: DEFAULT_LOG_LEVEL = 'info'; audit = new Audit(config, reporter, { groups: flags.groups || _constants().OWNED_DEPENDENCY_TYPES, level: flags.level || DEFAULT_LOG_LEVEL }); _context3.next = 4; return _lockfile()["default"].fromDirectory(config.lockfileFolder, reporter); case 4: lockfile = _context3.sent; install = new (_install().Install)({}, config, reporter, lockfile); _context3.next = 8; return install.fetchRequestFromCwd(); case 8: _yield$install$fetchR = _context3.sent; manifest = _yield$install$fetchR.manifest; requests = _yield$install$fetchR.requests; patterns = _yield$install$fetchR.patterns; workspaceLayout = _yield$install$fetchR.workspaceLayout; _context3.next = 15; return install.resolver.init(requests, { workspaceLayout: workspaceLayout }); case 15: _context3.next = 17; return audit.performAudit(manifest, lockfile, install.resolver, install.linker, patterns); case 17: vulnerabilities = _context3.sent; EXIT_INFO = 1; EXIT_LOW = 2; EXIT_MODERATE = 4; EXIT_HIGH = 8; EXIT_CRITICAL = 16; exitCode = (vulnerabilities.info ? EXIT_INFO : 0) + (vulnerabilities.low ? EXIT_LOW : 0) + (vulnerabilities.moderate ? EXIT_MODERATE : 0) + (vulnerabilities.high ? EXIT_HIGH : 0) + (vulnerabilities.critical ? EXIT_CRITICAL : 0); if (flags.summary) { audit.summary(); } else { audit.report(); } return _context3.abrupt("return", exitCode); case 26: case "end": return _context3.stop(); } }, _callee3); })); return _run.apply(this, arguments); } var Audit = /*#__PURE__*/function () { function Audit(config, reporter, options) { (0, _classCallCheck2()["default"])(this, Audit); (0, _defineProperty2()["default"])(this, "severityLevels", ['info', 'low', 'moderate', 'high', 'critical']); (0, _defineProperty2()["default"])(this, "config", void 0); (0, _defineProperty2()["default"])(this, "reporter", void 0); (0, _defineProperty2()["default"])(this, "options", void 0); (0, _defineProperty2()["default"])(this, "auditData", void 0); this.config = config; this.reporter = reporter; this.options = options; } (0, _createClass2()["default"])(Audit, [{ key: "_mapHoistedNodes", value: function _mapHoistedNodes(auditNode, hoistedNodes, transitiveDevDeps) { var _iterator = _createForOfIteratorHelper(hoistedNodes), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var node = _step.value; var pkg = node.manifest.pkg; var requires = Object.assign({}, pkg.dependencies || {}, pkg.optionalDependencies || {}); for (var _i = 0, _Object$keys = Object.keys(requires); _i < _Object$keys.length; _i++) { var name = _Object$keys[_i]; if (!requires[name]) { requires[name] = '*'; } } auditNode.dependencies[node.name] = { version: node.version, integrity: pkg._remote ? pkg._remote.integrity || '' : '', requires: requires, dependencies: {}, dev: transitiveDevDeps.has("".concat(node.name, "@").concat(node.version)) }; if (node.children) { this._mapHoistedNodes(auditNode.dependencies[node.name], node.children, transitiveDevDeps); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } }, { key: "_mapHoistedTreesToAuditTree", value: function _mapHoistedTreesToAuditTree(manifest, hoistedTrees, transitiveDevDeps) { var requiresGroups = this.options.groups.map(function (group) { return manifest[group] || {}; }); var auditTree = { name: manifest.name || undefined, version: manifest.version || undefined, install: [], remove: [], metadata: { //TODO: What do we send here? npm sends npm version, node version, etc. }, requires: Object.assign.apply(Object, [{}].concat((0, _toConsumableArray2()["default"])(requiresGroups))), integrity: undefined, dependencies: {}, dev: false }; this._mapHoistedNodes(auditTree, hoistedTrees, transitiveDevDeps); return auditTree; } }, { key: "_fetchAudit", value: function () { var _fetchAudit2 = (0, _asyncToGenerator2()["default"])( /*#__PURE__*/_regenerator()["default"].mark(function _callee(auditTree) { var responseJson, registry, requestBody, response; return _regenerator()["default"].wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: registry = _constants().YARN_REGISTRY; this.reporter.verbose("Audit Request: ".concat(JSON.stringify(auditTree, null, 2))); _context.next = 4; return gzip(JSON.stringify(auditTree)); case 4: requestBody = _context.sent; _context.next = 7; return this.config.requestManager.request({ url: "".concat(registry, "/-/npm/v1/security/audits"), method: 'POST', body: requestBody, headers: { 'Content-Encoding': 'gzip', 'Content-Type': 'application/json', Accept: 'application/json' } }); case 7: response = _context.sent; _context.prev = 8; responseJson = JSON.parse(response); _context.next = 15; break; case 12: _context.prev = 12; _context.t0 = _context["catch"](8); throw new Error("Unexpected audit response (Invalid JSON): ".concat(response)); case 15: if (responseJson.metadata) { _context.next = 17; break; } throw new Error("Unexpected audit response (Missing Metadata): ".concat(JSON.stringify(responseJson, null, 2))); case 17: this.reporter.verbose("Audit Response: ".concat(JSON.stringify(responseJson, null, 2))); return _context.abrupt("return", responseJson); case 19: case "end": return _context.stop(); } }, _callee, this, [[8, 12]]); })); function _fetchAudit(_x6) { return _fetchAudit2.apply(this, arguments); } return _fetchAudit; }() }, { key: "_insertWorkspacePackagesIntoManifest", value: function _insertWorkspacePackagesIntoManifest(manifest, resolver) { if (resolver.workspaceLayout) { var workspaceAggregatorName = resolver.workspaceLayout.virtualManifestName; var workspaceManifest = resolver.workspaceLayout.workspaces[workspaceAggregatorName].manifest; manifest.dependencies = Object.assign(manifest.dependencies || {}, workspaceManifest.dependencies); manifest.devDependencies = Object.assign(manifest.devDependencies || {}, workspaceManifest.devDependencies); manifest.optionalDependencies = Object.assign(manifest.optionalDependencies || {}, workspaceManifest.optionalDependencies); } } }, { key: "performAudit", value: function () { var _performAudit = (0, _asyncToGenerator2()["default"])( /*#__PURE__*/_regenerator()["default"].mark(function _callee2(manifest, lockfile, resolver, linker, patterns) { var transitiveDevDeps, hoistedTrees, auditTree; return _regenerator()["default"].wrap(function _callee2$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: this._insertWorkspacePackagesIntoManifest(manifest, resolver); transitiveDevDeps = (0, _getTransitiveDevDependencies().getTransitiveDevDependencies)(manifest, resolver.workspaceLayout, lockfile); _context2.next = 4; return (0, _hoistedTreeBuilder().buildTree)(resolver, linker, patterns); case 4: hoistedTrees = _context2.sent; auditTree = this._mapHoistedTreesToAuditTree(manifest, hoistedTrees, transitiveDevDeps); _context2.next = 8; return this._fetchAudit(auditTree); case 8: this.auditData = _context2.sent; return _context2.abrupt("return", this.auditData.metadata.vulnerabilities); case 10: case "end": return _context2.stop(); } }, _callee2, this); })); function performAudit(_x7, _x8, _x9, _x10, _x11) { return _performAudit.apply(this, arguments); } return performAudit; }() }, { key: "summary", value: function summary() { if (!this.auditData) { return; } this.reporter.auditSummary(this.auditData.metadata); } }, { key: "report", value: function report() { var _this = this; if (!this.auditData) { return; } var startLoggingAt = Math.max(0, this.severityLevels.indexOf(this.options.level)); var reportAdvisory = function reportAdvisory(resolution) { var advisory = _this.auditData.advisories[resolution.id.toString()]; if (_this.severityLevels.indexOf(advisory.severity) >= startLoggingAt) { _this.reporter.auditAdvisory(resolution, advisory); } }; if (Object.keys(this.auditData.advisories).length !== 0) { // let printedManualReviewHeader = false; this.auditData.actions.forEach(function (action) { action.resolves.forEach(reportAdvisory); /* The following block has been temporarily removed * because the actions returned by npm are not valid for yarn. * Removing this action reporting until we can come up with a way * to correctly resolve issues. */ // if (action.action === 'update' || action.action === 'install') { // // these advisories can be resolved automatically by running a yarn command // const recommendation: AuditActionRecommendation = { // cmd: `yarn upgrade ${action.module}@${action.target}`, // isBreaking: action.isMajor, // action, // }; // this.reporter.auditAction(recommendation); // action.resolves.forEach(reportAdvisory); // } // if (action.action === 'review') { // // these advisories cannot be resolved automatically and require manual review // if (!printedManualReviewHeader) { // this.reporter.auditManualReview(); // } // printedManualReviewHeader = true; // action.resolves.forEach(reportAdvisory); // } }); } this.summary(); } }]); return Audit; }(); exports["default"] = Audit; //# sourceMappingURL=audit.js.map