HEX
Server: Apache
System: Linux webd004.cluster130.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64
User: frenchy (106757)
PHP: 7.4.33
Disabled: _dyuweyrj4,_dyuweyrj4r,dl
Upload Files
File: /home/frenchy/www/french-american.org/current/node_modules/snyk/dist/lib/snyk-test/run-test.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("fs");
const pathUtil = require("path");
const moduleToObject = require("snyk-module");
const depGraphLib = require("@snyk/dep-graph");
const analytics = require("../analytics");
const config = require("../config");
const detect = require("../../lib/detect");
const plugins = require("../plugins");
const module_info_1 = require("../module-info");
const is_ci_1 = require("../is-ci");
const request = require("../request");
const snyk = require("../");
const spinner = require("../spinner");
const common = require("./common");
const gemfileLockToDependencies = require("../../lib/plugins/rubygems/gemfile-lock-to-dependencies");
const legacy_1 = require("./legacy");
const errors_1 = require("../errors");
const print_deps_1 = require("../print-deps");
const prune_1 = require("../prune");
const cli_interface_1 = require("@snyk/cli-interface");
const authentication_failed_error_1 = require("../errors/authentication-failed-error");
// tslint:disable-next-line:no-var-requires
const debug = require('debug')('snyk');
function runTest(packageManager, root, options) {
    return __awaiter(this, void 0, void 0, function* () {
        const results = [];
        const spinnerLbl = 'Querying vulnerabilities database...';
        try {
            const payloads = yield assemblePayloads(root, options);
            for (const payload of payloads) {
                const payloadPolicy = payload.body && payload.body.policy;
                const depGraph = payload.body && payload.body.depGraph;
                let dockerfilePackages;
                if (payload.body &&
                    payload.body.docker &&
                    payload.body.docker.dockerfilePackages) {
                    dockerfilePackages = payload.body.docker.dockerfilePackages;
                }
                yield spinner(spinnerLbl);
                analytics.add('depGraph', !!depGraph);
                analytics.add('isDocker', !!(payload.body && payload.body.docker));
                // Type assertion might be a lie, but we are correcting that below
                let res = (yield sendTestPayload(payload));
                if (depGraph) {
                    res = legacy_1.convertTestDepGraphResultToLegacy(res, // Double "as" required by Typescript for dodgy assertions
                    depGraph, packageManager, options.severityThreshold);
                    // For Node.js: inject additional information (for remediation etc.) into the response.
                    if (payload.modules) {
                        res.dependencyCount = payload.modules.numDependencies;
                        if (res.vulnerabilities) {
                            res.vulnerabilities.forEach((vuln) => {
                                if (payload.modules && payload.modules.pluck) {
                                    const plucked = payload.modules.pluck(vuln.from, vuln.name, vuln.version);
                                    vuln.__filename = plucked.__filename;
                                    vuln.shrinkwrap = plucked.shrinkwrap;
                                    vuln.bundled = plucked.bundled;
                                    // this is an edgecase when we're testing the directly vuln pkg
                                    if (vuln.from.length === 1) {
                                        return;
                                    }
                                    const parentPkg = moduleToObject(vuln.from[1]);
                                    const parent = payload.modules.pluck(vuln.from.slice(0, 2), parentPkg.name, parentPkg.version);
                                    vuln.parentDepType = parent.depType;
                                }
                            });
                        }
                    }
                }
                // TODO: is this needed? we filter on the other side already based on policy
                // this will move to be filtered server side soon & it will support `'ignore-policy'`
                analytics.add('vulns-pre-policy', res.vulnerabilities.length);
                res.filesystemPolicy = !!payloadPolicy;
                if (!options['ignore-policy']) {
                    res.policy = res.policy || payloadPolicy;
                    const policy = yield snyk.policy.loadFromText(res.policy);
                    res = policy.filter(res, root);
                }
                analytics.add('vulns', res.vulnerabilities.length);
                if (res.docker && dockerfilePackages) {
                    res.vulnerabilities = res.vulnerabilities.map((vuln) => {
                        const dockerfilePackage = dockerfilePackages[vuln.name.split('/')[0]];
                        if (dockerfilePackage) {
                            vuln.dockerfileInstruction =
                                dockerfilePackage.instruction;
                        }
                        vuln.dockerBaseImage = res.docker.baseImage;
                        return vuln;
                    });
                }
                if (options.docker &&
                    options.file &&
                    options['exclude-base-image-vulns']) {
                    res.vulnerabilities = res.vulnerabilities.filter((vuln) => vuln.dockerfileInstruction);
                }
                res.uniqueCount = countUniqueVulns(res.vulnerabilities);
                results.push(res);
            }
            return results;
        }
        catch (error) {
            debug('Error running test', { error });
            // handling denial from registry because of the feature flag
            // currently done for go.mod
            if (error.code === 403 && error.message.includes('Feature not allowed')) {
                throw errors_1.NoSupportedManifestsFoundError([root]);
            }
            throw new errors_1.FailedToRunTestError(error.userMessage ||
                error.message ||
                `Failed to test ${packageManager} project`, error.code);
        }
        finally {
            spinner.clear(spinnerLbl)();
        }
    });
}
function sendTestPayload(payload) {
    const filesystemPolicy = payload.body && !!payload.body.policy;
    return new Promise((resolve, reject) => {
        request(payload, (error, res, body) => {
            if (error) {
                return reject(error);
            }
            if (res.statusCode !== 200) {
                const err = handleTestHttpErrorResponse(res, body);
                return reject(err);
            }
            body.filesystemPolicy = filesystemPolicy;
            resolve(body);
        });
    });
}
function handleTestHttpErrorResponse(res, body) {
    const { statusCode } = res;
    let err;
    const userMessage = body && body.userMessage;
    switch (statusCode) {
        case 401:
        case 403:
            err = authentication_failed_error_1.AuthFailedError(userMessage, statusCode);
            err.innerError = body.stack;
            break;
        case 500:
            err = new errors_1.InternalServerError(userMessage);
            err.innerError = body.stack;
            break;
        default:
            err = new errors_1.FailedToGetVulnerabilitiesError(userMessage, statusCode);
            err.innerError = body.error;
    }
    return err;
}
function assemblePayloads(root, options) {
    let isLocal;
    if (options.docker) {
        isLocal = true;
    }
    else {
        // TODO: Refactor this check so we don't require files when tests are using mocks
        isLocal = fs.existsSync(root);
    }
    analytics.add('local', isLocal);
    if (isLocal) {
        return assembleLocalPayloads(root, options);
    }
    return assembleRemotePayloads(root, options);
}
// Force getDepsFromPlugin to return scannedProjects for processing in assembleLocalPayload
function getDepsFromPlugin(root, options) {
    return __awaiter(this, void 0, void 0, function* () {
        options.file = options.file || detect.detectPackageFile(root);
        if (!options.docker && !(options.file || options.packageManager)) {
            throw errors_1.NoSupportedManifestsFoundError([...root]);
        }
        const plugin = plugins.loadPlugin(options.packageManager, options);
        const moduleInfo = module_info_1.ModuleInfo(plugin, options.policy);
        const inspectRes = yield moduleInfo.inspect(root, options.file, Object.assign({}, options));
        if (!cli_interface_1.legacyPlugin.isMultiResult(inspectRes)) {
            if (!inspectRes.package) {
                // something went wrong if both are not present...
                throw Error(`error getting dependencies from ${options.packageManager} ` +
                    "plugin: neither 'package' nor 'scannedProjects' were found");
            }
            if (!inspectRes.package.targetFile && inspectRes.plugin) {
                inspectRes.package.targetFile = inspectRes.plugin.targetFile;
            }
            // We are using "options" to store some information returned from plugin that we need to use later,
            // but don't want to send to Registry in the Payload.
            // TODO(kyegupov): decouple inspect and payload so that we don't need this hack
            if (inspectRes.plugin.meta &&
                inspectRes.plugin.meta.allSubProjectNames &&
                inspectRes.plugin.meta.allSubProjectNames.length > 1) {
                options.advertiseSubprojectsCount =
                    inspectRes.plugin.meta.allSubProjectNames.length;
            }
            return {
                plugin: inspectRes.plugin,
                scannedProjects: [{ depTree: inspectRes.package }],
            };
        }
        else {
            // We are using "options" to store some information returned from plugin that we need to use later,
            // but don't want to send to Registry in the Payload.
            // TODO(kyegupov): decouple inspect and payload so that we don't need this hack
            options.subProjectNames = inspectRes.scannedProjects.map((scannedProject) => scannedProject.depTree.name);
            return inspectRes;
        }
    });
}
// Payload to send to the Registry for scanning a package from the local filesystem.
function assembleLocalPayloads(root, options) {
    return __awaiter(this, void 0, void 0, function* () {
        const analysisType = options.docker ? 'docker' : options.packageManager;
        const spinnerLbl = 'Analyzing ' +
            analysisType +
            ' dependencies for ' +
            (pathUtil.relative('.', pathUtil.join(root, options.file || '')) ||
                pathUtil.relative('..', '.') + ' project dir');
        try {
            const payloads = [];
            yield spinner(spinnerLbl);
            const deps = yield getDepsFromPlugin(root, options);
            analytics.add('pluginName', deps.plugin.name);
            for (const scannedProject of deps.scannedProjects) {
                const pkg = scannedProject.depTree;
                if (options['print-deps']) {
                    yield spinner.clear(spinnerLbl)();
                    print_deps_1.maybePrintDeps(options, pkg);
                }
                if (deps.plugin && deps.plugin.packageManager) {
                    options.packageManager = deps.plugin.packageManager;
                }
                if (pkg.docker) {
                    const baseImageFromDockerfile = pkg.docker.baseImage;
                    if (!baseImageFromDockerfile && options['base-image']) {
                        pkg.docker.baseImage = options['base-image'];
                    }
                    if (baseImageFromDockerfile && deps.plugin && deps.plugin.imageLayers) {
                        analytics.add('BaseImage', baseImageFromDockerfile);
                        analytics.add('imageLayers', deps.plugin.imageLayers);
                    }
                }
                if (_.get(pkg, 'files.gemfileLock.contents')) {
                    const gemfileLockBase64 = pkg.files.gemfileLock.contents;
                    const gemfileLockContents = Buffer.from(gemfileLockBase64, 'base64').toString();
                    pkg.dependencies = gemfileLockToDependencies(gemfileLockContents);
                }
                let policyLocations = [options['policy-path'] || root];
                if (options.docker) {
                    policyLocations = policyLocations.filter((loc) => {
                        return loc !== root;
                    });
                }
                else if (['npm', 'yarn'].indexOf(options.packageManager) > -1) {
                    policyLocations = policyLocations.concat(pluckPolicies(pkg));
                }
                debug('policies found', policyLocations);
                analytics.add('policies', policyLocations.length);
                analytics.add('packageManager', options.packageManager);
                addPackageAnalytics(pkg);
                let policy;
                if (policyLocations.length > 0) {
                    try {
                        policy = yield snyk.policy.load(policyLocations, options);
                    }
                    catch (err) {
                        // note: inline catch, to handle error from .load
                        //   if the .snyk file wasn't found, it is fine
                        if (err.code !== 'ENOENT') {
                            throw err;
                        }
                    }
                }
                let body = {
                    targetFile: pkg.targetFile,
                    projectNameOverride: options.projectName,
                    policy: policy && policy.toString(),
                    docker: pkg.docker,
                    hasDevDependencies: pkg.hasDevDependencies,
                };
                if (options.vulnEndpoint) {
                    // options.vulnEndpoint is only used by `snyk protect` (i.e. local filesystem tests).
                    body = Object.assign({}, body, pkg);
                }
                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,
                    });
                    let depGraph = yield depGraphLib.legacy.depTreeToGraph(pkg, options.packageManager);
                    debug('done converting dep-tree to dep-graph', {
                        uniquePkgsCount: depGraph.getPkgs().length,
                    });
                    if (options['prune-repeated-subdependencies']) {
                        debug('Trying to prune the graph');
                        const prePruneDepCount = prune_1.countPathsToGraphRoot(depGraph);
                        debug('pre prunedPathsCount: ' + prePruneDepCount);
                        depGraph = yield prune_1.pruneGraph(depGraph, options.packageManager);
                        analytics.add('prePrunedPathsCount', prePruneDepCount);
                        const postPruneDepCount = prune_1.countPathsToGraphRoot(depGraph);
                        debug('post prunedPathsCount: ' + postPruneDepCount);
                        analytics.add('postPrunedPathsCount', postPruneDepCount);
                    }
                    body.depGraph = depGraph;
                }
                const payload = {
                    method: 'POST',
                    url: config.API + (options.vulnEndpoint || '/test-dep-graph'),
                    json: true,
                    headers: {
                        'x-is-ci': is_ci_1.isCI(),
                        authorization: 'token ' + snyk.api,
                    },
                    qs: common.assembleQueryString(options),
                    body,
                };
                if (['yarn', 'npm'].indexOf(options.packageManager) !== -1) {
                    const isLockFileBased = options.file &&
                        (options.file.endsWith('package-lock.json') ||
                            options.file.endsWith('yarn.lock'));
                    if (!isLockFileBased || options.traverseNodeModules) {
                        payload.modules = pkg; // See the output of resolve-deps
                    }
                }
                payloads.push(payload);
            }
            return payloads;
        }
        finally {
            yield spinner.clear(spinnerLbl)();
        }
    });
}
// Payload to send to the Registry for scanning a remote package.
function assembleRemotePayloads(root, options) {
    return __awaiter(this, void 0, void 0, function* () {
        const pkg = moduleToObject(root);
        debug('testing remote: %s', pkg.name + '@' + pkg.version);
        addPackageAnalytics(pkg);
        const encodedName = encodeURIComponent(pkg.name + '@' + pkg.version);
        // options.vulnEndpoint is only used by `snyk protect` (i.e. local filesystem tests)
        const url = `${config.API}${options.vulnEndpoint ||
            `/vuln/${options.packageManager}`}/${encodedName}`;
        return [
            {
                method: 'GET',
                url,
                qs: common.assembleQueryString(options),
                json: true,
                headers: {
                    'x-is-ci': is_ci_1.isCI(),
                    authorization: 'token ' + snyk.api,
                },
            },
        ];
    });
}
function addPackageAnalytics(module) {
    analytics.add('packageName', module.name);
    analytics.add('packageVersion', module.version);
    analytics.add('package', module.name + '@' + module.version);
}
function countUniqueVulns(vulns) {
    const seen = {};
    for (const curr of vulns) {
        seen[curr.id] = true;
    }
    return Object.keys(seen).length;
}
function pluckPolicies(pkg) {
    if (!pkg) {
        return null;
    }
    if (pkg.snyk) {
        return pkg.snyk;
    }
    if (!pkg.dependencies) {
        return null;
    }
    return _.flatten(Object.keys(pkg.dependencies)
        .map((name) => {
        return pluckPolicies(pkg.dependencies[name]);
    })
        .filter(Boolean));
}
module.exports = runTest;
//# sourceMappingURL=run-test.js.map