@candrewsintegralblue/snyk
Version:
snyk library and cli utility
308 lines (292 loc) • 13.9 kB
JavaScript
"use strict";
exports.id = 27;
exports.ids = [27,875];
exports.modules = {
/***/ 24027:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
const cloneDeep = __webpack_require__(83465);
const path = __webpack_require__(71017);
const get = __webpack_require__(29208);
const chalk_1 = __webpack_require__(32589);
const detect_1 = __webpack_require__(45318);
const get_deps_from_plugin_1 = __webpack_require__(4842);
const spinner_1 = __webpack_require__(86766);
const process_command_args_1 = __webpack_require__(52369);
const types_1 = __webpack_require__(55246);
const theme_1 = __webpack_require__(86988);
const analytics = __webpack_require__(82744);
const Debug = __webpack_require__(15158);
const depGraphLib = __webpack_require__(71479);
const theme = __webpack_require__(86988);
const failed_to_run_client_sbom_error_1 = __webpack_require__(13490);
const errors_1 = __webpack_require__(55191);
const extract_package_manager_1 = __webpack_require__(22805);
const is_multi_project_scan_1 = __webpack_require__(62435);
const package_managers_1 = __webpack_require__(53847);
const cdx = __webpack_require__(27769);
const packageurl_js_1 = __webpack_require__(38382);
const print_deps_1 = __webpack_require__(79792);
const version_1 = __webpack_require__(74970);
const check_paths_1 = __webpack_require__(94501);
const prune_1 = __webpack_require__(87725);
const console_1 = __webpack_require__(96206);
const debug = Debug('snyk-client-sbom');
function validateProjectType(options, projectType) {
if (!((0, is_multi_project_scan_1.isMultiProjectScan)(options) || package_managers_1.SUPPORTED_PACKAGE_MANAGER_NAME[projectType])) {
throw new errors_1.UnsupportedPackageManagerError(projectType);
}
}
/**
* Generate a {@link https://github.com/package-url/purl-spec purl (Package URL)} for a given {@link depGraphLib.PkgInfo}.
* @param packageManager {@link SupportedPackageManagers} which discovered `dep`
* @param dep {@link depGraphLib.PkgInfo} package for which purl is to be generated
* @returns {@link PackageURL} for the given `dep`
* @see {@link https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst PURL Types Specification}
*/
function depToPackageURL(packageManager, dep) {
let namespace = undefined;
let name = dep.name;
let type;
switch (packageManager) {
case 'rubygems':
type = 'gem';
break;
case 'npm':
case 'pnpm':
case 'yarn':
type = 'npm';
break;
case 'maven':
case 'gradle':
case 'sbt': {
const splitName = dep.name.split(':', 2);
if (splitName.length == 1) {
namespace = undefined;
name = splitName[0];
}
else {
[namespace, name] = splitName;
}
type = 'maven';
break;
}
case 'pip':
case 'poetry':
type = 'pypi';
break;
case 'golangdep':
case 'gomodules':
case 'govendor':
type = 'golang';
break;
case 'nuget':
case 'paket':
type = 'nuget';
break;
case 'composer':
type = 'composer';
break;
case 'cocoapods':
type = 'carthage';
break;
case 'hex':
type = 'hex';
break;
case 'Unmanaged (C/C++)':
type = 'generic';
break;
case 'swift':
type = 'swift';
break;
default: {
const exhaustiveCheck = packageManager;
throw new Error(`Unhandled packageManager case: ${exhaustiveCheck}`);
}
}
return new packageurl_js_1.PackageURL(type, namespace, name, dep.version, undefined, undefined);
}
/**
* Create and add a {@link cdx.Models.Component} for the given {@link depGraphLib.PkgInfo} to the given {@link cdx.Models.Bom} if it hasn't already been created.
* @param dep the dep to add to `bom`
* @param packageURLToComponent map used to determine if a {@link cdx.Models.Component} has been previously created. Used to determine if a new {@link cdx.Models.Component} should be created or if an existing one should be used.
* @param packageManager {@link SupportedPackageManagers} which constructed `depGraph`
* @param targetFile path to the file from which the `depGraph` was derived.
* @param bom {@link cdx.Models.Bom} to which to add the component.
* @param depGraph {@link depGraphLib.DepGraph} that contains `dep`
* @returns the {@link cdx.Models.Component} representation of `dep`
*/
function component(dep, packageURLToComponent, packageManager, targetFile, bom, depGraph) {
var _a;
const packageURL = depToPackageURL(packageManager, dep);
const packageURLString = packageURL.toString();
if (!(packageURLString in packageURLToComponent)) {
const depComponent = new cdx.Models.Component(cdx.Enums.ComponentType.Library, packageURL.name, {
version: dep.version,
purl: packageURL,
group: (_a = packageURL.namespace) === null || _a === void 0 ? void 0 : _a.toString(),
bomRef: `${targetFile}:${packageURL}`,
});
// The "snyk" property namespace has been reserved: https://github.com/CycloneDX/cyclonedx-property-taxonomy
depComponent.properties.add(new cdx.Models.Property('snyk:package_manager:name', packageManager));
depComponent.properties.add(new cdx.Models.Property('snyk:source_file:path', targetFile));
packageURLToComponent[packageURLString] = depComponent;
bom.components.add(depComponent);
// dependency graph
if (depGraph.rootPkg !== dep) {
for (const pathToRoot of depGraph.pkgPathsToRoot(dep)) {
(0, console_1.assert)(pathToRoot.length > 1); // pathToRoot is always greater than 1 for non-root packages (and the root package isn't included)
(0, console_1.assert)(dep === pathToRoot[0]); // sanity check; the path to root always starts with the given package
const revDep = pathToRoot[1];
const revDepComponent = component(revDep, packageURLToComponent, packageManager, targetFile, bom, depGraph);
revDepComponent.dependencies.add(depComponent.bomRef);
}
}
}
return packageURLToComponent[packageURLString];
}
exports["default"] = async (...args) => {
const { options: originalOptions, paths } = (0, process_command_args_1.processCommandArgs)(...args);
debug(originalOptions);
(0, check_paths_1.checkOSSPaths)(paths, originalOptions);
const humanReadableArr = [];
const bom = new cdx.Models.Bom();
bom.metadata.tools.add(new cdx.Models.Tool({
vendor: 'Snyk',
name: 'snyk-cli',
version: await (0, version_1.default)(),
}));
const featureFlags = new Set([package_managers_1.PNPM_FEATURE_FLAG]);
// Promise waterfall to test all other paths sequentially
for (const root of paths) {
// Create a copy of the options so a specific test can
// modify them i.e. add `options.file` etc. We'll need
// these options later.
const options = cloneDeep(originalOptions);
options.path = root;
if (!options.allProjects) {
options.packageManager = (0, detect_1.detectPackageManager)(root, options, featureFlags);
}
const projectType = options.packageManager;
validateProjectType(options, projectType);
// For --all-projects packageManager is yet undefined here. Use 'all'
let analysisTypeText = 'all dependencies for ';
if (options.packageManager) {
analysisTypeText = options.packageManager + ' dependencies for ';
}
const spinnerLbl = 'Analyzing ' +
analysisTypeText +
(path.relative('.', path.join(root, options.file || '')) ||
path.relative('..', '.') + ' project dir');
try {
await spinner_1.spinner.clear(spinnerLbl)();
if (!options.quiet) {
await (0, spinner_1.spinner)(spinnerLbl);
}
const deps = await (0, get_deps_from_plugin_1.getDepsFromPlugin)(root, options, featureFlags);
const failedResults = deps.failedResults;
if (failedResults === null || failedResults === void 0 ? void 0 : failedResults.length) {
await spinner_1.spinner.clear(spinnerLbl)();
if (!options.json && !options.quiet) {
console.warn(chalk_1.default.bold.red(`${theme_1.icon.ISSUE} ${failedResults.length}/${failedResults.length +
deps.scannedProjects
.length} potential projects failed to get dependencies.`));
failedResults.forEach((f) => {
if (f.targetFile) {
console.warn(theme.color.status.error(`${f.targetFile}:`));
}
console.warn(theme.color.status.error(` ${f.errMessage}`));
});
}
debug('getDepsFromPlugin returned failed results, cannot run deps', failedResults);
if (options['fail-fast']) {
throw new failed_to_run_client_sbom_error_1.FailedToRunClientSbomError((0, errors_1.errorMessageWithRetry)('Your deps request could not be completed.'));
}
}
analytics.add('pluginName', deps.plugin.name);
const javaVersion = get(deps.plugin, 'meta.versionBuildInfo.metaBuildVersion.javaVersion', null);
const mvnVersion = get(deps.plugin, 'meta.versionBuildInfo.metaBuildVersion.mvnVersion', null);
const sbtVersion = get(deps.plugin, 'meta.versionBuildInfo.metaBuildVersion.sbtVersion', null);
if (javaVersion) {
analytics.add('javaVersion', javaVersion);
}
if (mvnVersion) {
analytics.add('mvnVersion', mvnVersion);
}
if (sbtVersion) {
analytics.add('sbtVersion', sbtVersion);
}
for (const scannedProject of deps.scannedProjects) {
const project = scannedProject;
const packageManager = (0, extract_package_manager_1.extractPackageManager)(project, deps, options);
const pkg = scannedProject.depGraph
? scannedProject.depGraph
: scannedProject.depTree;
let depGraph;
if (scannedProject.depGraph) {
depGraph = scannedProject.depGraph;
}
else {
// Graphs are more compact and robust representations.
// Legacy parts of the code are still using trees, but will eventually be fully migrated.
debug('converting dep-tree to dep-graph', {
name: pkg.name,
targetFile: scannedProject.targetFile || options.file,
});
depGraph = await depGraphLib.legacy.depTreeToGraph(pkg, packageManager);
debug('done converting dep-tree to dep-graph', {
uniquePkgsCount: depGraph.getDepPkgs().length,
});
}
(0, print_deps_1.maybePrintDepGraph)(options, depGraph);
depGraph = await (0, prune_1.pruneGraph)(depGraph, packageManager, options.pruneIsRequired);
const targetFile = path.relative('.', path.resolve(root, scannedProject.targetFile || options.file || '.'));
humanReadableArr.push(`${targetFile}: Found ${depGraph.getPkgs().length} ${depGraph.pkgManager.name} dependencies`);
const packageURLToComponent = new Map();
for (const dep of depGraph.getPkgs()) {
component(dep, packageURLToComponent, packageManager, targetFile, bom, depGraph);
}
}
}
finally {
await spinner_1.spinner.clear(spinnerLbl)();
}
}
const cyclonedxJsonResult = new cdx.Serialize.JsonSerializer(new cdx.Serialize.JSON.Normalize.Factory(cdx.Spec.Spec1dot4)).serialize(bom);
return types_1.ClientSbomCommandResult.createClientSbomCommandResult(originalOptions['cyclonedx-json']
? cyclonedxJsonResult
: humanReadableArr.join('\n'), cyclonedxJsonResult);
};
/***/ }),
/***/ 74970:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
const version_1 = __webpack_require__(38217);
async function version() {
let version = (0, version_1.getVersion)();
if ((0, version_1.isStandaloneBuild)()) {
version += ' (standalone)';
}
return version;
}
exports["default"] = version;
/***/ }),
/***/ 13490:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.FailedToRunClientSbomError = void 0;
const custom_error_1 = __webpack_require__(17188);
class FailedToRunClientSbomError extends custom_error_1.CustomError {
constructor(userMessage, errorCode) {
const code = errorCode || 500;
super(userMessage || FailedToRunClientSbomError.ERROR_MESSAGE);
this.code = errorCode || code;
this.userMessage = userMessage || FailedToRunClientSbomError.ERROR_MESSAGE;
}
}
exports.FailedToRunClientSbomError = FailedToRunClientSbomError;
FailedToRunClientSbomError.ERROR_MESSAGE = 'Failed to run client-sbom';
/***/ })
};
;
//# sourceMappingURL=27.index.js.map