UNPKG

snyk

Version:

snyk library and cli utility

1,220 lines (1,138 loc) • 311 kB
exports.id = 533; exports.ids = [533]; exports.modules = { /***/ 3196: /***/ ((module) => { function webpackEmptyContext(req) { var e = new Error("Cannot find module '" + req + "'"); e.code = 'MODULE_NOT_FOUND'; throw e; } webpackEmptyContext.keys = () => ([]); webpackEmptyContext.resolve = webpackEmptyContext; webpackEmptyContext.id = 3196; module.exports = webpackEmptyContext; /***/ }), /***/ 81024: /***/ ((__unused_webpack_module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.APP_VULNS_OPTION = exports.EXCLUDE_APP_VULNS_OPTION = exports.INCLUDE_SYSTEM_JARS_OPTION = exports.CONTAINER_CLI_APP_VULNS_ENABLED_FEATURE_FLAG = exports.SCAN_USR_LIB_JARS_FEATURE_FLAG = void 0; // Feature flag names exports.SCAN_USR_LIB_JARS_FEATURE_FLAG = 'scanUsrLibJars'; exports.CONTAINER_CLI_APP_VULNS_ENABLED_FEATURE_FLAG = 'containerCliAppVulnsEnabled'; // CLI option names exports.INCLUDE_SYSTEM_JARS_OPTION = 'include-system-jars'; exports.EXCLUDE_APP_VULNS_OPTION = 'exclude-app-vulns'; exports.APP_VULNS_OPTION = 'app-vulns'; /***/ }), /***/ 3708: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.validateTags = exports.generateTags = exports.generateProjectAttributes = exports.validateProjectAttributes = void 0; const chalk_1 = __webpack_require__(32589); const fs = __webpack_require__(57147); const Debug = __webpack_require__(15158); const pathUtil = __webpack_require__(71017); const cli_interface_1 = __webpack_require__(65266); const check_paths_1 = __webpack_require__(94501); const theme = __webpack_require__(86988); const types_1 = __webpack_require__(94055); const config_1 = __webpack_require__(25425); const detect = __webpack_require__(45318); const spinner_1 = __webpack_require__(86766); const analytics = __webpack_require__(82744); const api_token_1 = __webpack_require__(95181); const print_deps_1 = __webpack_require__(79792); const monitor_1 = __webpack_require__(3959); const process_json_monitor_1 = __webpack_require__(21506); const snyk = __webpack_require__(9146); const formatters_1 = __webpack_require__(81329); const get_deps_from_plugin_1 = __webpack_require__(4842); const get_extra_project_count_1 = __webpack_require__(34355); const extract_package_manager_1 = __webpack_require__(22805); const convert_multi_plugin_res_to_multi_custom_1 = __webpack_require__(23110); const convert_single_splugin_res_to_multi_custom_1 = __webpack_require__(99695); const dev_count_analysis_1 = __webpack_require__(73898); const errors_1 = __webpack_require__(55191); const is_multi_project_scan_1 = __webpack_require__(62435); const ecosystems_1 = __webpack_require__(5168); const monitor_2 = __webpack_require__(62406); const process_command_args_1 = __webpack_require__(52369); const feature_flags_1 = __webpack_require__(63011); const constants_1 = __webpack_require__(81024); const package_managers_1 = __webpack_require__(53847); const normalize_target_file_1 = __webpack_require__(97682); const SEPARATOR = '\n-------------------------------------------------------\n'; const debug = Debug('snyk'); const appVulnsReleaseWarningMsg = `${theme.icon.WARNING} Important: Beginning January 24th, 2023, application dependencies in container images will be scanned by default when using the snyk container test/monitor commands. If you are using Snyk in a CI pipeline, action may be required. Read https://snyk.io/blog/securing-container-applications-using-the-snyk-cli/ for more info.`; // This is used instead of `let x; try { x = await ... } catch { cleanup }` to avoid // declaring the type of x as possibly undefined. async function promiseOrCleanup(p, cleanup) { return p.catch((error) => { cleanup(); throw error; }); } // Returns an array of Registry responses (one per every sub-project scanned), a single response, // or an error message. async function monitor(...args0) { var _a; const { options, paths } = (0, process_command_args_1.processCommandArgs)(...args0); const results = []; if (options.id) { snyk.id = options.id; } if (options.allSubProjects && options['project-name']) { throw new Error('`--all-sub-projects` is currently not compatible with `--project-name`'); } if (!options.docker) { (0, check_paths_1.checkOSSPaths)(paths, options); } if (options.docker && options['remote-repo-url']) { throw new Error('`--remote-repo-url` is not supported for container scans'); } if (options.docker) { // order is important here, we want: // 1) exclude-app-vulns set -> no app vulns // 2) app-vulns set -> app-vulns // 3) neither set -> containerAppVulnsEnabled if (options[constants_1.EXCLUDE_APP_VULNS_OPTION]) { options[constants_1.EXCLUDE_APP_VULNS_OPTION] = true; } else if (options[constants_1.APP_VULNS_OPTION]) { options[constants_1.EXCLUDE_APP_VULNS_OPTION] = false; } else { options[constants_1.EXCLUDE_APP_VULNS_OPTION] = !(await (0, feature_flags_1.hasFeatureFlagOrDefault)(constants_1.CONTAINER_CLI_APP_VULNS_ENABLED_FEATURE_FLAG, options, false)); // we can't print the warning message with JSON output as that would make // the JSON output invalid. // We also only want to print the message if the user did not overwrite // the default with one of the flags. if (options[constants_1.EXCLUDE_APP_VULNS_OPTION] && !options['json'] && !options['sarif']) { console.log(theme.color.status.warn(appVulnsReleaseWarningMsg)); } } // Check scanUsrLibJars feature flag and add --include-system-jars parameter const scanUsrLibJarsEnabled = await (0, feature_flags_1.hasFeatureFlagOrDefault)(constants_1.SCAN_USR_LIB_JARS_FEATURE_FLAG, options, false); if (scanUsrLibJarsEnabled) { options[constants_1.INCLUDE_SYSTEM_JARS_OPTION] = true; } } // Handles no image arg provided to the container command until // a validation interface is implemented in the docker plugin. if (options.docker && paths.length === 0) { throw new errors_1.MissingArgError(); } (0, api_token_1.apiOrOAuthTokenExists)(); let contributors = []; if (!options.docker && analytics.allowAnalytics()) { try { contributors = await (0, dev_count_analysis_1.getContributors)(); } catch (err) { debug('error getting repo contributors', err); } } const ecosystem = (0, ecosystems_1.getEcosystem)(options); if (ecosystem) { const commandResult = await (0, ecosystems_1.monitorEcosystem)(ecosystem, paths, options, contributors); const [monitorResults, monitorErrors] = commandResult; return await (0, monitor_2.getFormattedMonitorOutput)(results, monitorResults, monitorErrors, options); } let hasPnpmSupport = false; let hasImprovedDotnetWithoutPublish = false; let enableMavenDverboseExhaustiveDeps = false; try { hasPnpmSupport = (await (0, feature_flags_1.hasFeatureFlag)(package_managers_1.PNPM_FEATURE_FLAG, options)); if (options['dotnet-runtime-resolution']) { hasImprovedDotnetWithoutPublish = (await (0, feature_flags_1.hasFeatureFlag)(package_managers_1.DOTNET_WITHOUT_PUBLISH_FEATURE_FLAG, options)); } } catch (err) { hasPnpmSupport = false; } try { const args = options['_doubleDashArgs'] || []; const verboseEnabled = args.includes('-Dverbose') || args.includes('-Dverbose=true') || !!options['print-graph']; if (verboseEnabled) { enableMavenDverboseExhaustiveDeps = (await (0, feature_flags_1.hasFeatureFlag)(package_managers_1.MAVEN_DVERBOSE_EXHAUSTIVE_DEPS_FF, options)); if (enableMavenDverboseExhaustiveDeps) { options.mavenVerboseIncludeAllVersions = enableMavenDverboseExhaustiveDeps; } } } catch (err) { enableMavenDverboseExhaustiveDeps = false; } const featureFlags = hasPnpmSupport ? new Set([package_managers_1.PNPM_FEATURE_FLAG]) : new Set(); if (hasImprovedDotnetWithoutPublish) { options.useImprovedDotnetWithoutPublish = true; } // Part 1: every argument is a scan target; process them sequentially for (const path of paths) { debug(`Processing ${path}...`); try { validateMonitorPath(path, options.docker); let analysisType = 'all'; let packageManager; if ((0, is_multi_project_scan_1.isMultiProjectScan)(options)) { analysisType = 'all'; } else if (options.docker) { analysisType = 'docker'; } else { packageManager = detect.detectPackageManager(path, options, featureFlags); } const unsupportedPackageManagers = []; const unsupportedPackageManager = unsupportedPackageManagers.find((pm) => pm.name === packageManager); if (unsupportedPackageManager) { return `${unsupportedPackageManager.label} projects do not currently support "snyk monitor"`; } const targetFile = !options.scanAllUnmanaged && options.docker && !options.file // snyk monitor --docker (without --file) ? undefined : options.file || detect.detectPackageFile(path, featureFlags); const displayPath = pathUtil.relative('.', pathUtil.join(path, targetFile || '')); const analyzingDepsSpinnerLabel = 'Analyzing ' + (packageManager ? packageManager : analysisType) + ' dependencies for ' + displayPath; await (0, spinner_1.spinner)(analyzingDepsSpinnerLabel); // Scan the project dependencies via a plugin debug('getDepsFromPlugin ...'); // each plugin will be asked to scan once per path // some return single InspectResult & newer ones return Multi const inspectResult = await promiseOrCleanup((0, get_deps_from_plugin_1.getDepsFromPlugin)(path, { ...options, path, packageManager, }, featureFlags), spinner_1.spinner.clear(analyzingDepsSpinnerLabel)); analytics.add('pluginName', inspectResult.plugin.name); // We send results from "all-sub-projects" scanning as different Monitor objects // multi result will become default, so start migrating code to always work with it let perProjectResult; if (!cli_interface_1.legacyPlugin.isMultiResult(inspectResult)) { perProjectResult = (0, convert_single_splugin_res_to_multi_custom_1.convertSingleResultToMultiCustom)(inspectResult); } else { perProjectResult = (0, convert_multi_plugin_res_to_multi_custom_1.convertMultiResultToMultiCustom)(inspectResult); } const failedResults = inspectResult .failedResults; if (failedResults === null || failedResults === void 0 ? void 0 : failedResults.length) { failedResults.forEach((result) => { results.push({ ok: false, data: new errors_1.MonitorError(500, result.errMessage), path: result.targetFile || '', }); }); } const postingMonitorSpinnerLabel = 'Posting monitor snapshot for ' + displayPath + ' ...'; await (0, spinner_1.spinner)(postingMonitorSpinnerLabel); // Post the project dependencies to the Registry for (const projectDeps of perProjectResult.scannedProjects) { try { if (!projectDeps.depGraph && !projectDeps.depTree) { debug('scannedProject is missing depGraph or depTree, cannot run test/monitor'); throw new errors_1.FailedToRunTestError('Your monitor request could not be completed. Please email support@snyk.io'); } const extractedPackageManager = (0, extract_package_manager_1.extractPackageManager)(projectDeps, perProjectResult, options); analytics.add('packageManager', extractedPackageManager); const projectName = getProjectName(projectDeps); if (projectDeps.depGraph) { debug(`Processing ${(_a = projectDeps.depGraph.rootPkg) === null || _a === void 0 ? void 0 : _a.name}...`); (0, print_deps_1.maybePrintDepGraph)(options, projectDeps.depGraph); } if (projectDeps.depTree) { debug(`Processing ${projectDeps.depTree.name}...`); (0, print_deps_1.maybePrintDepTree)(options, projectDeps.depTree); } const tFile = (0, normalize_target_file_1.normalizeTargetFile)(projectDeps, projectDeps.plugin, targetFile); const targetFileRelativePath = tFile ? pathUtil.resolve(pathUtil.resolve(path), tFile) : ''; const res = await promiseOrCleanup((0, monitor_1.monitor)(path, generateMonitorMeta(options, extractedPackageManager), projectDeps, options, projectDeps.plugin, targetFileRelativePath, contributors, generateProjectAttributes(options), generateTags(options)), spinner_1.spinner.clear(postingMonitorSpinnerLabel)); res.path = path; const monOutput = (0, formatters_1.formatMonitorOutput)(extractedPackageManager, res, options, projectName, await (0, get_extra_project_count_1.getExtraProjectCount)(path, options, inspectResult)); // push a good result results.push({ ok: true, data: monOutput, path, projectName }); } catch (err) { // pushing this error allow this inner loop to keep scanning the projects // even if 1 in 100 fails results.push({ ok: false, data: err, path }); } } } catch (err) { // push this error, the loop continues results.push({ ok: false, data: err, path }); } finally { spinner_1.spinner.clearAll(); } } // Part 2: process the output from the Registry if (options.json) { return (0, process_json_monitor_1.processJsonMonitorResponse)(results); } const output = results .map((res) => { if (res.ok) { return res.data; } const errorMessage = res.data && res.data.userMessage ? chalk_1.default.bold.red(res.data.userMessage) : res.data ? res.data.message : 'Unknown error occurred.'; return (chalk_1.default.bold.white('\nMonitoring ' + res.path + '...\n\n') + errorMessage); }) .join('\n' + SEPARATOR); if (results.every((res) => res.ok)) { return output; } throw new Error(output); } exports["default"] = monitor; function generateMonitorMeta(options, packageManager) { return { method: 'cli', packageManager, 'policy-path': options['policy-path'], 'project-name': options['project-name'] || config_1.default.PROJECT_NAME, isDocker: !!options.docker, prune: !!options.pruneRepeatedSubdependencies, 'remote-repo-url': options['remote-repo-url'], targetReference: options['target-reference'], assetsProjectName: options['assets-project-name'], reachabilityScanId: options['reachability-id'], }; } /** * Parse an attribute from the CLI into the relevant enum type. * * @param attribute The project attribute (e.g. environment) * @param permitted Permitted options * @param options CLI options provided * @returns An array of attributes to set on the project or undefined to mean "do not touch". */ function getProjectAttribute(attribute, permitted, options) { const permittedValues = Object.values(permitted); if (options[attribute] === undefined) { return undefined; } // Explicit flag to clear the existing values for this attribute already set on the project // e.g. if you specify --environment= // then this means you want to remove existing environment values on the project. if (options[attribute] === '') { return []; } // When it's specified without the =, we raise an explicit error to avoid // accidentally clearing the existing values. if (options[attribute] === true) { throw new errors_1.ValidationError(`--${attribute} must contain an '=' with a comma-separated list of values. To clear all existing values, pass no values i.e. --${attribute}=`); } const values = options[attribute].split(','); const extra = values.filter((value) => !permittedValues.includes(value)); if (extra.length > 0) { throw new errors_1.ValidationError(`${extra.length} invalid ${attribute}: ${extra.join(', ')}. ` + `Possible values are: ${permittedValues.join(', ')}`); } return values; } function validateProjectAttributes(options) { // The validation is deep within the parsing, so call the generate but throw away the return for simplicity. // Using this method makes it much clearer what the intent is of the caller. generateProjectAttributes(options); } exports.validateProjectAttributes = validateProjectAttributes; function generateProjectAttributes(options) { return { criticality: getProjectAttribute('project-business-criticality', types_1.PROJECT_CRITICALITY, options), environment: getProjectAttribute('project-environment', types_1.PROJECT_ENVIRONMENT, options), lifecycle: getProjectAttribute('project-lifecycle', types_1.PROJECT_LIFECYCLE, options), }; } exports.generateProjectAttributes = generateProjectAttributes; /** * Parse CLI --tags options into an internal data structure. * * If this returns undefined, it means "do not touch the existing tags on the project". * * Anything else means "replace existing tags on the project with this list" even if empty. * * @param options CLI options * @returns List of parsed tags or undefined if they are to be left untouched. */ function generateTags(options) { if (options['project-tags'] === undefined && options['tags'] === undefined) { return undefined; } if (options['project-tags'] !== undefined && options['tags'] !== undefined) { throw new errors_1.ValidationError('Only one of --tags or --project-tags may be specified, not both'); } const rawTags = options['tags'] === undefined ? options['project-tags'] : options['tags']; if (rawTags === '') { return []; } // When it's specified without the =, we raise an explicit error to avoid // accidentally clearing the existing tags; if (rawTags === true) { throw new errors_1.ValidationError(`--project-tags must contain an '=' with a comma-separated list of pairs (also separated with an '='). To clear all existing values, pass no values i.e. --project-tags=`); } const keyEqualsValuePairs = rawTags.split(','); const tags = []; for (const keyEqualsValue of keyEqualsValuePairs) { const parts = keyEqualsValue.split('='); if (parts.length !== 2) { throw new errors_1.ValidationError(`The tag "${keyEqualsValue}" does not have an "=" separating the key and value. For example: --project-tags=KEY=VALUE`); } tags.push({ key: parts[0], value: parts[1], }); } return tags; } exports.generateTags = generateTags; function validateTags(options) { // The validation is deep within the parsing, so call the generate but throw away the return for simplicity. // Using this method makes it much clearer what the intent is of the caller. generateTags(options); } exports.validateTags = validateTags; function validateMonitorPath(path, isDocker) { const exists = fs.existsSync(path); if (!exists && !isDocker) { throw new Error('"' + path + '" is not a valid path for "snyk monitor"'); } } function getProjectName(projectDeps) { var _a, _b, _c, _d; return (((_a = projectDeps.meta) === null || _a === void 0 ? void 0 : _a.gradleProjectName) || ((_c = (_b = projectDeps.depGraph) === null || _b === void 0 ? void 0 : _b.rootPkg) === null || _c === void 0 ? void 0 : _c.name) || ((_d = projectDeps.depTree) === null || _d === void 0 ? void 0 : _d.name)); } /***/ }), /***/ 21506: /***/ ((__unused_webpack_module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.processJsonMonitorResponse = void 0; function processJsonMonitorResponse(results) { let dataToSend = results.map((result) => { if (result.ok) { const jsonData = JSON.parse(result.data); if (result.projectName) { jsonData.projectName = result.projectName; } return jsonData; } return { ok: false, error: result.data.message, path: result.path }; }); // backwards compat - strip array if only one result dataToSend = dataToSend.length === 1 ? dataToSend[0] : dataToSend; const stringifiedData = JSON.stringify(dataToSend, null, 2); if (results.every((res) => res.ok)) { return stringifiedData; } const err = new Error(stringifiedData); err.json = stringifiedData; throw err; } exports.processJsonMonitorResponse = processJsonMonitorResponse; /***/ }), /***/ 52369: /***/ ((__unused_webpack_module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.processCommandArgs = void 0; function processCommandArgs(...args) { let options = {}; if (typeof args[args.length - 1] === 'object') { options = args.pop(); } args = args.filter(Boolean); // For repository scanning, populate with default path (cwd) if no path given if (args.length === 0 && !options.docker) { args.unshift(process.cwd()); } return { options, paths: args }; } exports.processCommandArgs = processCommandArgs; /***/ }), /***/ 55246: /***/ ((__unused_webpack_module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.TestCommandResult = exports.CommandResult = void 0; class CommandResult { constructor(result) { this.result = result; } toString() { return this.result; } getDisplayResults() { return this.result; } } exports.CommandResult = CommandResult; class TestCommandResult extends CommandResult { constructor() { super(...arguments); this.jsonResult = ''; this.sarifResult = ''; this.jsonData = {}; } getJsonResult() { return this.jsonResult; } getSarifResult() { return this.sarifResult; } getJsonData() { return this.jsonData; } static createHumanReadableTestCommandResult(humanReadableResult, jsonResult, sarifResult, jsonData) { return new HumanReadableTestCommandResult(humanReadableResult, jsonResult, sarifResult, jsonData); } static createJsonTestCommandResult(stdout, jsonResult, sarifResult, jsonPayload) { return new JsonTestCommandResult(stdout, jsonResult, sarifResult, jsonPayload); } } exports.TestCommandResult = TestCommandResult; class HumanReadableTestCommandResult extends TestCommandResult { constructor(humanReadableResult, jsonResult, sarifResult, jsonData) { super(humanReadableResult); this.jsonResult = ''; this.sarifResult = ''; this.jsonData = {}; this.jsonResult = jsonResult; if (sarifResult) { this.sarifResult = sarifResult; } if (jsonData) { this.jsonData = jsonData; } } getJsonResult() { return this.jsonResult; } getSarifResult() { return this.sarifResult; } getJsonData() { return this.jsonData; } } class JsonTestCommandResult extends TestCommandResult { constructor(stdout, jsonResult, sarifResult, jsonData) { super(stdout); if (jsonResult) { this.jsonResult = jsonResult; } if (sarifResult) { this.sarifResult = sarifResult; } else { this.jsonResult = stdout; } if (jsonData) { this.jsonData = jsonData; } } getJsonResult() { return this.jsonResult; } getSarifResult() { return this.sarifResult; } } /***/ }), /***/ 94501: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.checkOSSPaths = void 0; const errors_1 = __webpack_require__(55191); const detect_1 = __webpack_require__(45318); // Throw error if user specifies package file name as part of path, // and if user specifies multiple paths and used project-name option. function checkOSSPaths(paths, options) { let count = 0; for (const path of paths) { if (typeof path === 'string' && (0, detect_1.isPathToPackageFile)(path)) { throw (0, errors_1.MissingTargetFileError)(path); } else if (typeof path === 'string') { if (++count > 1 && options['project-name']) { throw new errors_1.UnsupportedOptionCombinationError([ 'multiple paths', 'project-name', ]); } } } } exports.checkOSSPaths = checkOSSPaths; /***/ }), /***/ 55203: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getCodeClientProxyUrl = void 0; const config_1 = __webpack_require__(25425); function getCodeClientProxyUrl() { const url = new URL(config_1.default.API); const domain = url.origin; const routeToAPI = isFedramp(domain); return (config_1.default.CODE_CLIENT_PROXY_URL || domain.replace(/\/\/(ap[pi]\.)?/, routeToAPI ? '//api.' : '//deeproxy.')); } exports.getCodeClientProxyUrl = getCodeClientProxyUrl; function isFedramp(domain) { return domain.includes('snykgov.io'); } /***/ }), /***/ 73399: /***/ ((__unused_webpack_module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.hasUnknownVersions = void 0; function hasUnknownVersions(depGraph) { if (!depGraph) { return false; } for (const pkg of depGraph.getPkgs()) { if (pkg.version === 'unknown') { return true; } } return false; } exports.hasUnknownVersions = hasUnknownVersions; /***/ }), /***/ 69813: /***/ ((__unused_webpack_module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.isUnmanagedEcosystem = void 0; function isUnmanagedEcosystem(ecosystem) { return ecosystem === 'cpp'; } exports.isUnmanagedEcosystem = isUnmanagedEcosystem; /***/ }), /***/ 5168: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getEcosystem = exports.getEcosystemForTest = exports.getPlugin = exports.monitorEcosystem = exports.testEcosystem = void 0; var test_1 = __webpack_require__(60937); Object.defineProperty(exports, "testEcosystem", ({ enumerable: true, get: function () { return test_1.testEcosystem; } })); var monitor_1 = __webpack_require__(62406); Object.defineProperty(exports, "monitorEcosystem", ({ enumerable: true, get: function () { return monitor_1.monitorEcosystem; } })); var plugins_1 = __webpack_require__(78053); Object.defineProperty(exports, "getPlugin", ({ enumerable: true, get: function () { return plugins_1.getPlugin; } })); /** * Ecosystems are listed here if you opt in to the new plugin test flow. * This is a breaking change to the old plugin formats, so only a select few * plugins currently work with it. * * Currently container scanning is not yet ready to work with this flow, * hence this is in a separate function from getEcosystem(). */ function getEcosystemForTest(options) { if (options.unmanaged) { return 'cpp'; } if (options.code) { return 'code'; } return null; } exports.getEcosystemForTest = getEcosystemForTest; function getEcosystem(options) { if (options.unmanaged) { return 'cpp'; } if (options.docker) { return 'docker'; } return null; } exports.getEcosystem = getEcosystem; /***/ }), /***/ 62406: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getFormattedMonitorOutput = exports.generateMonitorDependenciesRequest = exports.monitorEcosystem = void 0; const chalk_1 = __webpack_require__(32589); const config_1 = __webpack_require__(25425); const is_ci_1 = __webpack_require__(10090); const promise_1 = __webpack_require__(90430); const spinner_1 = __webpack_require__(86766); const plugins_1 = __webpack_require__(78053); const process_json_monitor_1 = __webpack_require__(21506); const formatters_1 = __webpack_require__(81329); const get_extra_project_count_1 = __webpack_require__(34355); const errors_1 = __webpack_require__(55191); const policy_1 = __webpack_require__(4669); const api_token_1 = __webpack_require__(95181); const resolve_monitor_facts_1 = __webpack_require__(47630); const monitor_1 = __webpack_require__(3708); const common_1 = __webpack_require__(69813); const policy_2 = __webpack_require__(32615); const SEPARATOR = '\n-------------------------------------------------------\n'; async function monitorEcosystem(ecosystem, paths, options, contributors) { const plugin = (0, plugins_1.getPlugin)(ecosystem); (0, monitor_1.validateTags)(options); (0, monitor_1.validateProjectAttributes)(options); const scanResultsByPath = {}; for (const path of paths) { try { await (0, spinner_1.spinner)(`Analyzing dependencies in ${path}`); options.path = path; const pluginResponse = await plugin.scan(options); scanResultsByPath[path] = pluginResponse.scanResults; const policy = await (0, policy_2.findAndLoadPolicy)(path, 'cpp', options); if (policy) { scanResultsByPath[path].forEach((scanResult) => (scanResult.policy = policy.toString())); } } catch (error) { if (ecosystem === 'docker' && error.statusCode === 401 && error.message === 'authentication required') { throw new errors_1.DockerImageNotFoundError(path); } if (ecosystem === 'docker' && error.message === 'invalid image format') { throw new errors_1.DockerImageNotFoundError(path); } throw error; } finally { spinner_1.spinner.clearAll(); } } const [monitorResults, errors] = await selectAndExecuteMonitorStrategy(ecosystem, scanResultsByPath, options, contributors); return [monitorResults, errors]; } exports.monitorEcosystem = monitorEcosystem; async function selectAndExecuteMonitorStrategy(ecosystem, scanResultsByPath, options, contributors) { return (0, common_1.isUnmanagedEcosystem)(ecosystem) ? await (0, resolve_monitor_facts_1.resolveAndMonitorFacts)(scanResultsByPath, options, contributors) : await monitorDependencies(scanResultsByPath, options); } async function generateMonitorDependenciesRequest(scanResult, options) { // WARNING! This mutates the payload. The project name logic should be handled in the plugin. scanResult.name = options['project-name'] || config_1.default.PROJECT_NAME || scanResult.name; scanResult.targetReference = options['target-reference']; // WARNING! This mutates the payload. Policy logic should be in the plugin. const policy = await (0, policy_1.findAndLoadPolicyForScanResult)(scanResult, options); if (policy !== undefined) { scanResult.policy = policy.toString(); } return { scanResult, method: 'cli', projectName: options['project-name'] || config_1.default.PROJECT_NAME || undefined, tags: (0, monitor_1.generateTags)(options), attributes: (0, monitor_1.generateProjectAttributes)(options), pruneRepeatedSubdependencies: options.pruneRepeatedSubdependencies, }; } exports.generateMonitorDependenciesRequest = generateMonitorDependenciesRequest; async function monitorDependencies(scans, options) { const results = []; const errors = []; for (const [path, scanResults] of Object.entries(scans)) { await (0, spinner_1.spinner)(`Monitoring dependencies in ${path}`); for (const scanResult of scanResults) { const monitorDependenciesRequest = await generateMonitorDependenciesRequest(scanResult, options); const configOrg = config_1.default.org ? decodeURIComponent(config_1.default.org) : undefined; const payload = { method: 'PUT', url: `${config_1.default.API}/monitor-dependencies`, json: true, headers: { 'x-is-ci': (0, is_ci_1.isCI)(), authorization: (0, api_token_1.getAuthHeader)(), }, body: monitorDependenciesRequest, qs: { org: options.org || configOrg, }, }; try { const response = await (0, promise_1.makeRequest)(payload); results.push({ ...response, path, scanResult, }); } catch (error) { if (error.code === 401) { throw (0, errors_1.AuthFailedError)(); } if (error.code >= 400 && error.code < 500) { throw new errors_1.MonitorError(error.code, error.message); } errors.push({ error: 'Could not monitor dependencies in ' + path, path, scanResult, }); } } spinner_1.spinner.clearAll(); } return [results, errors]; } async function getFormattedMonitorOutput(results, monitorResults, errors, options) { for (const monitorResult of monitorResults) { let monOutput = ''; if (monitorResult.ok) { monOutput = (0, formatters_1.formatMonitorOutput)(monitorResult.scanResult.identity.type, monitorResult, options, monitorResult.projectName, await (0, get_extra_project_count_1.getExtraProjectCount)(monitorResult.path, options, // TODO: Fix to pass the old "inspectResult.plugin.meta.allSubProjectNames", which ecosystem uses this? // "allSubProjectNames" can become a Fact returned by a plugin. {})); } else { monOutput = (0, formatters_1.formatErrorMonitorOutput)(monitorResult.scanResult.identity.type, monitorResult, options); } results.push({ ok: true, data: monOutput, path: monitorResult.path, projectName: monitorResult.id, }); } for (const monitorError of errors) { results.push({ ok: false, data: new errors_1.MonitorError(500, monitorError.error), path: monitorError.path, }); } if (options.json) { return (0, process_json_monitor_1.processJsonMonitorResponse)(results); } const outputString = results .map((res) => { if (res.ok) { return res.data; } const errorMessage = res.data && res.data.userMessage ? chalk_1.default.bold.red(res.data.userMessage) : res.data ? res.data.message : 'Unknown error occurred.'; return (chalk_1.default.bold.white('\nMonitoring ' + res.path + '...\n\n') + errorMessage); }) .join('\n' + SEPARATOR); if (results.every((res) => res.ok)) { return outputString; } throw new Error(outputString); } exports.getFormattedMonitorOutput = getFormattedMonitorOutput; /***/ }), /***/ 33077: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.extractAndApplyPluginAnalytics = void 0; const analytics = __webpack_require__(82744); function extractAndApplyPluginAnalytics(pluginAnalytics, asyncRequestToken) { if (asyncRequestToken) { analytics.add('asyncRequestToken', asyncRequestToken); } for (const { name, data } of pluginAnalytics) { analytics.add(name, data); } } exports.extractAndApplyPluginAnalytics = extractAndApplyPluginAnalytics; /***/ }), /***/ 78053: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getPlugin = void 0; const cppPlugin = __webpack_require__(96957); const dockerPlugin = __webpack_require__(61165); const sast_1 = __webpack_require__(93221); const EcosystemPlugins = { cpp: cppPlugin, // TODO: not any docker: dockerPlugin, code: sast_1.codePlugin, }; function getPlugin(ecosystem) { return EcosystemPlugins[ecosystem]; } exports.getPlugin = getPlugin; /***/ }), /***/ 4669: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.filterIgnoredIssues = exports.findAndLoadPolicyForScanResult = void 0; const path = __webpack_require__(71017); const policy_1 = __webpack_require__(32615); async function findAndLoadPolicyForScanResult(scanResult, options) { const targetFileRelativePath = scanResult.identity.targetFile ? path.join(path.resolve(`${options.path}`), scanResult.identity.targetFile) : undefined; const targetFileDir = targetFileRelativePath ? path.parse(targetFileRelativePath).dir : undefined; const scanType = options.docker ? 'docker' : scanResult.identity.type; // TODO: fix this and send only send when we used resolve-deps for node // it should be a ExpandedPkgTree type instead const packageExpanded = undefined; const policy = (await (0, policy_1.findAndLoadPolicy)(options.path, scanType, options, packageExpanded, targetFileDir)); // TODO: findAndLoadPolicy() does not return a string! return policy; } exports.findAndLoadPolicyForScanResult = findAndLoadPolicyForScanResult; function filterIgnoredIssues(issues, issuesData, policy) { if (!(policy === null || policy === void 0 ? void 0 : policy.ignore)) { return [issues, issuesData]; } const filteredIssuesData = { ...issuesData }; const filteredIssues = issues.filter((issue) => { const ignoredIssue = policy.ignore[issue.issueId]; if (!ignoredIssue) { return true; } const allResourcesRule = ignoredIssue.find((element) => '*' in element); if (!allResourcesRule) { return true; } const expiredIgnoreRule = allResourcesRule['*'].expires && new Date(allResourcesRule['*'].expires) < new Date(); if (!expiredIgnoreRule) { delete filteredIssuesData[issue.issueId]; return false; } return true; }); return [filteredIssues, filteredIssuesData]; } exports.filterIgnoredIssues = filterIgnoredIssues; /***/ }), /***/ 47630: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveAndMonitorFacts = void 0; const spinner_1 = __webpack_require__(86766); const polling_monitor_1 = __webpack_require__(59354); const plugin_analytics_1 = __webpack_require__(33077); const errors_1 = __webpack_require__(55191); const common_1 = __webpack_require__(74434); async function resolveAndMonitorFacts(scans, options, contributors) { const results = []; const errors = []; for (const [path, scanResults] of Object.entries(scans)) { await (0, spinner_1.spinner)(`Resolving and Monitoring fileSignatures in ${path}`); for (const scanResult of scanResults) { try { const res = await (0, polling_monitor_1.requestMonitorPollingToken)(options, true, scanResult); if (scanResult.analytics) { (0, plugin_analytics_1.extractAndApplyPluginAnalytics)(scanResult.analytics, res.token); } const resolutionMeta = (0, common_1.extractResolutionMetaFromScanResult)(scanResult); const { maxAttempts, pollInterval } = res.pollingTask; const attemptsCount = 0; const response = await (0, polling_monitor_1.pollingMonitorWithTokenUntilDone)(res.token, true, options, pollInterval, attemptsCount, maxAttempts, resolutionMeta, contributors); const ecosystemMonitorResult = { ...response, path, scanResult, }; results.push(ecosystemMonitorResult); } catch (error) { if (error.code === 401) { throw (0, errors_1.AuthFailedError)(); } if (error.code >= 400 && error.code < 500) { throw new errors_1.MonitorError(error.code, error.message); } errors.push({ error: 'Could not monitor dependencies in ' + path, path, scanResult, }); } } spinner_1.spinner.clearAll(); } return [results, errors]; } exports.resolveAndMonitorFacts = resolveAndMonitorFacts; /***/ }), /***/ 85164: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveAndTestFactsRegistry = exports.resolveAndTestFactsUnmanagedDeps = exports.pollDepGraphAttributes = exports.submitHashes = exports.resolveAndTestFacts = void 0; const spinner_1 = __webpack_require__(86766); const common_1 = __webpack_require__(70527); const errors_1 = __webpack_require__(55191); const policy_1 = __webpack_require__(32615); const polling_test_1 = __webpack_require__(77584); const common_2 = __webpack_require__(53110); const plugin_analytics_1 = __webpack_require__(33077); const policy_2 = __webpack_require__(4669); const utils_1 = __webpack_require__(97875); async function resolveAndTestFacts(ecosystem, scans, options) { try { return await resolveAndTestFactsUnmanagedDeps(scans, options); } catch (error) { const unauthorizedErrorCode = error.code === 401 || error.code === 403; const missingApiToken = error.isMissingApiToken; // Decide if the error is an authorization error other than being // unauthenticated (missing or invalid API token). An account lacking // permission, for example. const otherUnauthorized = unauthorizedErrorCode && !missingApiToken; if (otherUnauthorized) { throw (0, errors_1.AuthFailedError)('Unauthorized request to unmanaged service', error.code); } throw error; } } exports.resolveAndTestFacts = resolveAndTestFacts; async function submitHashes(hashes, orgId) { const response = await (0, polling_test_1.createDepGraph)(hashes, orgId); return response.data.id; } exports.submitHashes = submitHashes; async function pollDepGraphAttributes(id, orgId) { const minIntervalMs = 2000; const maxIntervalMs = 20000; let totalElaspedTime = 0; let attempts = 1; const maxElapsedTime = 1800000; // 30 mins in ms // Loop until we receive a response that is not in progress, // or we receive something else than http status code 200. while (totalElaspedTime <= maxElapsedTime) { const graph = await (0, polling_test_1.getDepGraph)(id, orgId); if (graph.data.attributes.in_progress) { const pollInterval = Math.min(minIntervalMs * attempts, maxIntervalMs); await (0, common_1.sleep)(pollInterval); totalElaspedTime += pollInterval; attempts++; continue; } return graph.data.attributes; } throw new Error('max retries reached'); } exports.pollDepGraphAttributes = pollDepGraphAttributes; async function fetchIssues(start_time, dep_graph_data, component_details, target_severity, orgId) { var _a, _b; const response = await (0, polling_test_1.getIssues)({ dep_graph: dep_graph_data, start_time, component_details, target_severity, }, orgId); const issues = response.data.result.issues.map((issue) => { const converted = (0, utils_1.convertToCamelCase)(issue); converted.fixInfo = (0, utils_1.convertToCamelCase)(converted.fixInfo); return converted; }); const issuesData = (0, utils_1.convertMapCasing)(response.data.result.issues_data); const depGraphData = (0, utils_1.convertDepGraph)(response.data.result.dep_graph); const dependencyCount = (_b = (_a = response.data.result.dep_graph.graph.nodes.find((graphNode) => { return graphNode.node_id === 'root-node'; })) === null || _a === void 0 ? void 0 : _a.deps) === null || _b === void 0 ? void 0 : _b.length; const depsFilePaths = response.data.result.deps_file_paths; const fileSignaturesDetails = (0, utils_1.convertMapCasing)(response.data.result.file_signatures_details); return { issues, issuesData, depGraphData, dependencyCount, depsFilePaths, fileSignaturesDetails, }; } function buildVulnerabilityFromIssue(issueData, issue, packageManager) { const pkgCoordinate = `${issue.pkgName}@${issue.pkgVersion}`; issueData.from = [pkgCoordinate]; issueData.name = pkgCoordinate; issueData.packageManager = packageManager; issueData.version = issue.pkgVersion || ''; issueData.upgradePath = [false]; issueData.isPatchable = false; return issueData; } async function resolveAndTestFactsUnmanagedDeps(scans, options) { var _a, _b, _c, _d; const results = []; const errors = []; const packageManager = 'Unmanaged (C/C++)'; const displayTargetFile = ''; const orgId = await (0, utils_1.getOrg)(options.org); const target_severity = options.severityThreshold || common_2.SEVERITY.LOW; if (orgId === '') { errors.push('organisation-id missing'); return [results, errors]; } for (const [path, scanResults] of Object.entries(scans)) { await (0, spinner_1.spinner)(`Resolving and Testing fileSignatures in ${path}`); for (const scanResult of scanResults) { try { const id = await submitHashes({ hashes: (_a = scanResult === null || scanResult === void 0 ? void 0 : scanResult.facts[0]) === null || _a === void 0 ? void 0 : _a.data }, orgId); if (scanResult.analytics) { (0, plugin_analytics_1.extractAndApplyPluginAnalytics)(scanResult.analytics, id); } const { start_time, dep_graph_data, component_details } = await pollDepGraphAttributes(id, orgId); const { issues, issuesData, depGraphData, dependencyCount, depsFilePaths, fileSignaturesDetails, } = await fetchIssues(start_time, dep_graph_data, component_details, target_severity, orgId); const issuesMap = new Map(); issues.forEach((i) => { issuesMap.set(i.issueId, i); }); const policy = await (0, policy_1.findAndLoadPolicy)(path, 'cpp', options); const [issuesFiltered, issuesDataFiltered] = (0, policy_2.filterIgnoredIssues)(issues, issuesData, policy); // Build vulnerabilities array from filtered data. const vulnerabilities = []; for (const issuesDataKey in issuesDataFiltered) { const issue = issuesMap.get(issuesDataKey); if (issue) { const issueData = issuesDataFiltered[issuesDataKey]; vulnerabilities.push(buildVulnerabilityFromIssue(issueData, issue, packageManager)); } } // Build filtered.ignore array with ignored vulnerabilities const filteredIgnore = []; for (const issuesDataKey in issuesData) { // If the issue was in the original data but not in the filtered data, it was ignored if (!(issuesDataKey in issuesDataFiltered)) { const issue = issuesMap.get(issuesDataKey); if (issue) { const issueData = {