File: /home/f/r/e/frenchy/www/french-american.org/current/node_modules/snyk/dist/cli/commands/monitor.js
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const _ = require("lodash");
const fs = require("then-fs");
const api_token_1 = require("../../lib/api-token");
const snyk = require("../../lib/"); // TODO(kyegupov): fix import
const monitor_1 = require("../../lib/monitor");
const config = require("../../lib/config");
const url = require("url");
const chalk_1 = require("chalk");
const pathUtil = require("path");
const spinner = require("../../lib/spinner");
const detect = require("../../lib/detect");
const plugins = require("../../lib/plugins");
const module_info_1 = require("../../lib/module-info"); // TODO(kyegupov): fix import
const print_deps_1 = require("../../lib/print-deps");
const analytics = require("../../lib/analytics");
const errors_1 = require("../../lib/errors");
const cli_interface_1 = require("@snyk/cli-interface");
const feature_flags_1 = require("../../lib/feature-flags");
const SEPARATOR = '\n-------------------------------------------------------\n';
// This is used instead of `let x; try { x = await ... } catch { cleanup }` to avoid
// declaring the type of x as possibly undefined.
function promiseOrCleanup(p, cleanup) {
return __awaiter(this, void 0, void 0, function* () {
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.
function monitor(...args0) {
return __awaiter(this, void 0, void 0, function* () {
let args = [...args0];
let options = {};
const results = [];
if (typeof args[args.length - 1] === 'object') {
options = args.pop();
}
args = args.filter(Boolean);
// populate with default path (cwd) if no path given
if (args.length === 0) {
args.unshift(process.cwd());
}
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 && options['remote-repo-url']) {
throw new Error('`--remote-repo-url` is not supported for container scans');
}
api_token_1.apiTokenExists();
if (options['experimental-dep-graph']) {
const isFFSupported = yield feature_flags_1.isFeatureFlagSupportedForOrg(_.camelCase('experimental-dep-graph'));
if (!isFFSupported.ok) {
throw new errors_1.UnsupportedFeatureFlagError('experimental-dep-graph', isFFSupported.userMessage);
}
}
// Part 1: every argument is a scan target; process them sequentially
for (const path of args) {
try {
const exists = yield fs.exists(path);
if (!exists && !options.docker) {
throw new Error('"' + path + '" is not a valid path for "snyk monitor"');
}
let packageManager = detect.detectPackageManager(path, options);
const targetFile = options.docker && !options.file // snyk monitor --docker (without --file)
? undefined
: options.file || detect.detectPackageFile(path);
const plugin = plugins.loadPlugin(packageManager, options);
const moduleInfo = module_info_1.ModuleInfo(plugin, options.policy);
const displayPath = pathUtil.relative('.', pathUtil.join(path, targetFile || ''));
const analysisType = options.docker ? 'docker' : packageManager;
const analyzingDepsSpinnerLabel = 'Analyzing ' + analysisType + ' dependencies for ' + displayPath;
const postingMonitorSpinnerLabel = 'Posting monitor snapshot for ' + displayPath + ' ...';
yield spinner(analyzingDepsSpinnerLabel);
// Scan the project dependencies via a plugin
analytics.add('packageManager', packageManager);
analytics.add('pluginOptions', options);
// TODO: the type should depend on allSubProjects flag
const inspectResult = yield promiseOrCleanup(moduleInfo.inspect(path, targetFile, Object.assign({}, options)), spinner.clear(analyzingDepsSpinnerLabel));
analytics.add('pluginName', inspectResult.plugin.name);
yield spinner.clear(analyzingDepsSpinnerLabel)(inspectResult);
yield spinner(postingMonitorSpinnerLabel);
if (inspectResult.plugin.packageManager) {
packageManager = inspectResult.plugin.packageManager;
}
const meta = {
method: 'cli',
packageManager: packageManager,
'policy-path': options['policy-path'],
'project-name': options['project-name'] || config.PROJECT_NAME,
isDocker: !!options.docker,
prune: !!options['prune-repeated-subdependencies'],
'experimental-dep-graph': !!options['experimental-dep-graph'],
'remote-repo-url': options['remote-repo-url'],
};
// We send results from "all-sub-projects" scanning as different Monitor objects
// SinglePackageResult is a legacy format understood by Registry, so we have to convert
// a MultiProjectResult to an array of these.
let perSubProjectResults = [];
let advertiseSubprojectsCount = null;
if (cli_interface_1.legacyPlugin.isMultiResult(inspectResult)) {
perSubProjectResults = inspectResult.scannedProjects.map((scannedProject) => ({
plugin: inspectResult.plugin,
package: scannedProject.depTree,
}));
}
else {
if (!options['gradle-sub-project'] &&
inspectResult.plugin.meta &&
inspectResult.plugin.meta.allSubProjectNames &&
inspectResult.plugin.meta.allSubProjectNames.length > 1) {
advertiseSubprojectsCount =
inspectResult.plugin.meta.allSubProjectNames.length;
}
perSubProjectResults = [inspectResult];
}
// Post the project dependencies to the Registry
for (const subProjDeps of perSubProjectResults) {
print_deps_1.maybePrintDeps(options, subProjDeps.package);
const res = yield promiseOrCleanup(monitor_1.monitor(path, meta, subProjDeps, targetFile), spinner.clear(postingMonitorSpinnerLabel));
yield spinner.clear(postingMonitorSpinnerLabel)(res);
res.path = path;
const endpoint = url.parse(config.API);
let leader = '';
if (res.org) {
leader = '/org/' + res.org;
}
endpoint.pathname = leader + '/manage';
const manageUrl = url.format(endpoint);
endpoint.pathname = leader + '/monitor/' + res.id;
const subProjectName = cli_interface_1.legacyPlugin.isMultiResult(inspectResult)
? subProjDeps.package.name
: undefined;
const monOutput = formatMonitorOutput(packageManager, res, manageUrl, options, subProjectName, advertiseSubprojectsCount);
results.push({ ok: true, data: monOutput, path, subProjectName });
}
// push a good result
}
catch (err) {
// push this error, the loop continues
results.push({ ok: false, data: err, path });
}
}
// Part 2: process the output from the Registry
if (options.json) {
let dataToSend = results.map((result) => {
if (result.ok) {
const jsonData = JSON.parse(result.data);
if (result.subProjectName) {
jsonData.subProjectName = result.subProjectName;
}
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 json = JSON.stringify(dataToSend, null, 2);
if (results.every((res) => res.ok)) {
return json;
}
throw new Error(json);
}
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);
});
}
function formatMonitorOutput(packageManager, res, manageUrl, options, subProjectName, advertiseSubprojectsCount) {
const issues = res.licensesPolicy ? 'issues' : 'vulnerabilities';
const humanReadableName = subProjectName
? `${res.path} (${subProjectName})`
: res.path;
const strOutput = chalk_1.default.bold.white('\nMonitoring ' + humanReadableName + '...\n\n') +
(packageManager === 'yarn'
? 'A yarn.lock file was detected - continuing as a Yarn project.\n'
: '') +
'Explore this snapshot at ' +
res.uri +
'\n\n' +
(advertiseSubprojectsCount
? chalk_1.default.bold.white(`This project has multiple sub-projects (${advertiseSubprojectsCount}), ` +
'use --all-sub-projects flag to scan all sub-projects.\n\n')
: '') +
(res.isMonitored
? 'Notifications about newly disclosed ' +
issues +
' related ' +
'to these dependencies will be emailed to you.\n'
: chalk_1.default.bold.red('Project is inactive, so notifications are turned ' +
'off.\nActivate this project here: ' +
manageUrl +
'\n\n')) +
(res.trialStarted
? chalk_1.default.yellow("You're over the free plan usage limit, \n" +
'and are now on a free 14-day premium trial.\n' +
'View plans here: ' +
manageUrl +
'\n\n')
: '');
return options.json
? JSON.stringify(_.assign({}, res, {
manageUrl,
packageManager,
}))
: strOutput;
}
module.exports = monitor;
//# sourceMappingURL=monitor.js.map