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/cli/commands/test/index.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 chalk_1 = require("chalk");
const snyk = require("../../../lib");
const config = require("../../../lib/config");
const is_ci_1 = require("../../../lib/is-ci");
const api_token_1 = require("../../../lib/api-token");
const common_1 = require("../../../lib/snyk-test/common");
const Debug = require("debug");
const detect_1 = require("../../../lib/detect");
const legacy_format_issue_1 = require("./formatters/legacy-format-issue");
const package_managers_1 = require("../../../lib/package-managers");
const remediation_based_format_issues_1 = require("./formatters/remediation-based-format-issues");
const debug = Debug('snyk');
const SEPARATOR = '\n-------------------------------------------------------\n';
const showVulnPathsMapping = {
    false: 'none',
    none: 'none',
    true: 'some',
    some: 'some',
    all: 'all',
};
// TODO: avoid using `as any` whenever it's possible
function test(...args) {
    return __awaiter(this, void 0, void 0, function* () {
        const resultOptions = [];
        let results = [];
        let options = {};
        if (typeof args[args.length - 1] === 'object') {
            options = args.pop();
        }
        // populate with default path (cwd) if no path given
        if (args.length === 0) {
            args.unshift(process.cwd());
        }
        // org fallback to config unless specified
        options.org = options.org || config.org;
        // making `show-vulnerable-paths` 'some' by default.
        const svpSupplied = (options['show-vulnerable-paths'] || '').toLowerCase();
        options.showVulnPaths = showVulnPathsMapping[svpSupplied] || 'some';
        if (options.severityThreshold &&
            !validateSeverityThreshold(options.severityThreshold)) {
            return Promise.reject(new Error('INVALID_SEVERITY_THRESHOLD'));
        }
        api_token_1.apiTokenExists();
        // Promise waterfall to test all other paths sequentially
        for (const path of args) {
            // 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 testOpts = _.cloneDeep(options);
            testOpts.path = path;
            testOpts.projectName = testOpts['project-name'];
            let res;
            try {
                res = (yield snyk.test(path, testOpts));
            }
            catch (error) {
                // Possible error cases:
                // - the test found some vulns. `error.message` is a
                // JSON-stringified
                //   test result.
                // - the flow failed, `error` is a real Error object.
                // - the flow failed, `error` is a number or string
                // describing the problem.
                //
                // To standardise this, make sure we use the best _object_ to
                // describe the error.
                if (error instanceof Error) {
                    res = error;
                }
                else if (typeof error !== 'object') {
                    res = new Error(error);
                }
                else {
                    try {
                        res = JSON.parse(error.message);
                    }
                    catch (unused) {
                        res = error;
                    }
                }
            }
            // Not all test results are arrays in order to be backwards compatible
            // with scripts that use a callback with test. Coerce results/errors to be arrays
            // and add the result options to each to be displayed
            const resArray = Array.isArray(res) ? res : [res];
            for (let i = 0; i < resArray.length; i++) {
                results.push(_.assign(resArray[i], { path }));
                // currently testOpts are identical for each test result returned even if it's for multiple projects.
                // we want to return the project names, so will need to be crafty in a way that makes sense.
                if (!testOpts.subProjectNames) {
                    resultOptions.push(testOpts);
                }
                else {
                    resultOptions.push(_.assign(_.cloneDeep(testOpts), {
                        subProjectName: testOpts.subProjectNames[i],
                    }));
                }
            }
        }
        const vulnerableResults = results.filter((res) => res.vulnerabilities && res.vulnerabilities.length);
        const errorResults = results.filter((res) => res instanceof Error);
        const notSuccess = errorResults.length > 0;
        const foundVulnerabilities = vulnerableResults.length > 0;
        // resultOptions is now an array of 1 or more options used for
        // the tests results is now an array of 1 or more test results
        // values depend on `options.json` value - string or object
        if (options.json) {
            results = results.map((result) => {
                // add json for when thrown exception
                if (result instanceof Error) {
                    return {
                        ok: false,
                        error: result.message,
                        path: result.path,
                    };
                }
                return result;
            });
            // backwards compat - strip array IFF only one result
            const dataToSend = results.length === 1 ? results[0] : results;
            const stringifiedError = JSON.stringify(dataToSend, null, 2);
            if (results.every((res) => res.ok)) {
                return stringifiedError;
            }
            const err = new Error(stringifiedError);
            if (foundVulnerabilities) {
                err.code = 'VULNS';
                const dataToSendNoVulns = dataToSend;
                delete dataToSendNoVulns.vulnerabilities;
                err.jsonNoVulns = dataToSendNoVulns;
            }
            err.json = stringifiedError;
            throw err;
        }
        let response = results
            .map((unused, i) => displayResult(results[i], resultOptions[i]))
            .join(`\n${SEPARATOR}`);
        if (notSuccess) {
            debug(`Failed to test ${errorResults.length} projects, errors:`);
            errorResults.forEach((err) => {
                const errString = err.stack ? err.stack.toString() : err.toString();
                debug('error: %s', errString);
            });
        }
        let summaryMessage = '';
        if (results.length > 1) {
            const projects = results.length === 1 ? 'project' : 'projects';
            summaryMessage =
                `\n\n\nTested ${results.length} ${projects}` +
                    summariseVulnerableResults(vulnerableResults, options) +
                    summariseErrorResults(errorResults) +
                    '\n';
        }
        if (notSuccess) {
            response += chalk_1.default.bold.red(summaryMessage);
            const error = new Error(response);
            // take the code of the first problem to go through error
            // translation
            // HACK as there can be different errors, and we pass only the
            // first one
            error.code = errorResults[0].code;
            error.userMessage = errorResults[0].userMessage;
            throw error;
        }
        if (foundVulnerabilities) {
            response += chalk_1.default.bold.red(summaryMessage);
            const error = new Error(response);
            // take the code of the first problem to go through error
            // translation
            // HACK as there can be different errors, and we pass only the
            // first one
            error.code = vulnerableResults[0].code || 'VULNS';
            error.userMessage = vulnerableResults[0].userMessage;
            throw error;
        }
        response += chalk_1.default.bold.green(summaryMessage);
        return response;
    });
}
function summariseVulnerableResults(vulnerableResults, options) {
    const vulnsLength = vulnerableResults.length;
    if (vulnsLength) {
        if (options.showVulnPaths) {
            return `, ${vulnsLength} contained vulnerable paths.`;
        }
        return `, ${vulnsLength} had issues.`;
    }
    if (options.showVulnPaths) {
        return ', no vulnerable paths were found.';
    }
    return ', no issues were found.';
}
function summariseErrorResults(errorResults) {
    const projects = errorResults.length > 1 ? 'projects' : 'project';
    if (errorResults.length > 0) {
        return (` Failed to test ${errorResults.length} ${projects}.\n` +
            'Run with `-d` for debug output and contact support@snyk.io');
    }
    return '';
}
function displayResult(res, options) {
    const meta = metaForDisplay(res, options);
    const dockerAdvice = dockerRemediationForDisplay(res);
    const packageManager = options.packageManager;
    const localPackageTest = detect_1.isLocalFolder(options.path);
    const prefix = chalk_1.default.bold.white('\nTesting ' + options.path + '...\n\n');
    // handle errors by extracting their message
    if (res instanceof Error) {
        return prefix + res.message;
    }
    const issuesText = res.licensesPolicy ? 'issues' : 'vulnerabilities';
    let pathOrDepsText = '';
    if (res.hasOwnProperty('dependencyCount')) {
        pathOrDepsText += res.dependencyCount + ' dependencies';
    }
    else {
        pathOrDepsText += options.path;
    }
    const testedInfoText = `Tested ${pathOrDepsText} for known ${issuesText}`;
    let multiProjAdvice = '';
    if (options.advertiseSubprojectsCount) {
        multiProjAdvice = chalk_1.default.bold.white(`\n\nThis project has multiple sub-projects (${options.advertiseSubprojectsCount}), ` +
            'use --all-sub-projects flag to scan all sub-projects.');
    }
    // OK  => no vulns found, return
    if (res.ok && res.vulnerabilities.length === 0) {
        const vulnPathsText = options.showVulnPaths
            ? 'no vulnerable paths found.'
            : 'none were found.';
        const summaryOKText = chalk_1.default.green(`✓ ${testedInfoText}, ${vulnPathsText}`);
        const nextStepsText = localPackageTest
            ? '\n\nNext steps:' +
                '\n- Run `snyk monitor` to be notified ' +
                'about new related vulnerabilities.' +
                '\n- Run `snyk test` as part of ' +
                'your CI/test.'
            : '';
        // user tested a package@version and got 0 vulns back, but there were dev deps
        // to consider
        const snykPackageTestTip = !(options.docker ||
            localPackageTest ||
            options.dev)
            ? '\n\nTip: Snyk only tests production dependencies by default. You can try re-running with the `--dev` flag.'
            : '';
        return (prefix +
            meta +
            '\n\n' +
            summaryOKText +
            multiProjAdvice +
            (is_ci_1.isCI() ? '' : dockerAdvice + nextStepsText + snykPackageTestTip));
    }
    // NOT OK => We found some vulns, let's format the vulns info
    const vulnCount = res.vulnerabilities && res.vulnerabilities.length;
    const singleVulnText = res.licensesPolicy ? 'issue' : 'vulnerability';
    const multipleVulnsText = res.licensesPolicy ? 'issues' : 'vulnerabilities';
    // Text will look like so:
    // 'found 232 vulnerabilities, 404 vulnerable paths.'
    let vulnCountText = `found ${res.uniqueCount} ` +
        (res.uniqueCount === 1 ? singleVulnText : multipleVulnsText);
    // Docker is currently not supported as num of paths is inaccurate due to trimming of paths to reduce size.
    if (options.showVulnPaths && !options.docker) {
        vulnCountText += `, ${vulnCount} vulnerable `;
        if (vulnCount === 1) {
            vulnCountText += 'path.';
        }
        else {
            vulnCountText += 'paths.';
        }
    }
    else {
        vulnCountText += '.';
    }
    const summary = testedInfoText + ', ' + chalk_1.default.red.bold(vulnCountText);
    let wizardAdvice = '';
    if (localPackageTest &&
        package_managers_1.WIZARD_SUPPORTED_PACKAGE_MANAGERS.includes(packageManager)) {
        wizardAdvice = chalk_1.default.bold.green('\n\nRun `snyk wizard` to address these issues.');
    }
    let dockerSuggestion = '';
    if (options.docker && config.disableSuggestions !== 'true') {
        const optOutSuggestions = '\n\nTo remove this message in the future, please run `snyk config set disableSuggestions=true`';
        if (!options.file) {
            dockerSuggestion +=
                chalk_1.default.bold.white('\n\nPro tip: use `--file` option to get base image remediation advice.' +
                    `\nExample: $ snyk test --docker ${options.path} --file=path/to/Dockerfile`) + optOutSuggestions;
        }
        else if (!options['exclude-base-image-vulns']) {
            dockerSuggestion +=
                chalk_1.default.bold.white('\n\nPro tip: use `--exclude-base-image-vulns` to exclude from display Docker base image vulnerabilities.') + optOutSuggestions;
        }
    }
    const vulns = res.vulnerabilities || [];
    const groupedVulns = groupVulnerabilities(vulns);
    const sortedGroupedVulns = _.orderBy(groupedVulns, ['metadata.severityValue', 'metadata.name'], ['asc', 'desc']);
    const filteredSortedGroupedVulns = sortedGroupedVulns.filter((vuln) => vuln.metadata.packageManager !== 'upstream');
    const binariesSortedGroupedVulns = sortedGroupedVulns.filter((vuln) => vuln.metadata.packageManager === 'upstream');
    let groupedVulnInfoOutput;
    if (res.remediation) {
        groupedVulnInfoOutput = remediation_based_format_issues_1.formatIssuesWithRemediation(filteredSortedGroupedVulns, res.remediation, options);
    }
    else {
        groupedVulnInfoOutput = filteredSortedGroupedVulns.map((vuln) => legacy_format_issue_1.formatIssues(vuln, options));
    }
    const groupedDockerBinariesVulnInfoOutput = res.docker && binariesSortedGroupedVulns.length
        ? formatDockerBinariesIssues(binariesSortedGroupedVulns, res.docker.binariesVulns, options)
        : [];
    let body = groupedVulnInfoOutput.join('\n\n') +
        '\n\n' +
        groupedDockerBinariesVulnInfoOutput.join('\n\n') +
        '\n\n' +
        meta;
    if (res.remediation) {
        body = summary + body + wizardAdvice;
    }
    else {
        body = body + '\n\n' + summary + wizardAdvice;
    }
    const ignoredIssues = '';
    return (prefix +
        body +
        multiProjAdvice +
        ignoredIssues +
        dockerAdvice +
        dockerSuggestion);
}
function formatDockerBinariesIssues(dockerBinariesSortedGroupedVulns, binariesVulns, options) {
    const binariesIssuesOutput = [];
    for (const pkgInfo of _.values(binariesVulns.affectedPkgs)) {
        binariesIssuesOutput.push(createDockerBinaryHeading(pkgInfo));
        const binaryIssues = dockerBinariesSortedGroupedVulns.filter((vuln) => vuln.metadata.name === pkgInfo.pkg.name);
        const formattedBinaryIssues = binaryIssues.map((vuln) => legacy_format_issue_1.formatIssues(vuln, options));
        binariesIssuesOutput.push(formattedBinaryIssues.join('\n\n'));
    }
    return binariesIssuesOutput;
}
function createDockerBinaryHeading(pkgInfo) {
    const binaryName = pkgInfo.pkg.name;
    const binaryVersion = pkgInfo.pkg.version;
    const numOfVulns = _.values(pkgInfo.issues).length;
    const vulnCountText = numOfVulns > 1 ? 'vulnerabilities' : 'vulnerability';
    return numOfVulns
        ? chalk_1.default.bold.white(`------------ Detected ${numOfVulns} ${vulnCountText}` +
            ` for ${binaryName}@${binaryVersion} ------------`, '\n')
        : '';
}
function rightPadWithSpaces(s, desiredLength) {
    const padLength = desiredLength - s.length;
    if (padLength <= 0) {
        return s;
    }
    return s + ' '.repeat(padLength);
}
function metaForDisplay(res, options) {
    const padToLength = 19; // chars to align
    const packageManager = options.packageManager || res.packageManager;
    const openSource = res.isPrivate ? 'no' : 'yes';
    const meta = [
        chalk_1.default.bold(rightPadWithSpaces('Organization: ', padToLength)) + res.org,
        chalk_1.default.bold(rightPadWithSpaces('Package manager: ', padToLength)) +
            packageManager,
    ];
    if (options.file) {
        meta.push(chalk_1.default.bold(rightPadWithSpaces('Target file: ', padToLength)) +
            options.file);
    }
    if (options.subProjectName) {
        meta.push(chalk_1.default.bold(rightPadWithSpaces('Sub project: ', padToLength)) +
            options.subProjectName);
    }
    if (options.docker) {
        meta.push(chalk_1.default.bold(rightPadWithSpaces('Docker image: ', padToLength)) +
            options.path);
    }
    else {
        meta.push(chalk_1.default.bold(rightPadWithSpaces('Open source: ', padToLength)) + openSource);
        meta.push(chalk_1.default.bold(rightPadWithSpaces('Project path: ', padToLength)) +
            options.path);
    }
    if (res.docker && res.docker.baseImage) {
        meta.push(chalk_1.default.bold(rightPadWithSpaces('Base image: ', padToLength)) +
            res.docker.baseImage);
    }
    if (res.filesystemPolicy) {
        meta.push(chalk_1.default.bold(rightPadWithSpaces('Local Snyk policy: ', padToLength)) +
            chalk_1.default.green('found'));
        if (res.ignoreSettings && res.ignoreSettings.disregardFilesystemIgnores) {
            meta.push(chalk_1.default.bold(rightPadWithSpaces('Local Snyk policy ignored: ', padToLength)) + chalk_1.default.red('yes'));
        }
    }
    if (res.licensesPolicy) {
        meta.push(chalk_1.default.bold(rightPadWithSpaces('Licenses: ', padToLength)) +
            chalk_1.default.green('enabled'));
    }
    return meta.join('\n');
}
function dockerRemediationForDisplay(res) {
    if (!res.docker || !res.docker.baseImageRemediation) {
        return '';
    }
    const { advice, message } = res.docker.baseImageRemediation;
    const out = [];
    if (advice) {
        for (const item of advice) {
            out.push(getTerminalStringFormatter(item)(item.message));
        }
    }
    else if (message) {
        out.push(message);
    }
    else {
        return '';
    }
    return `\n\n${out.join('\n')}`;
}
function getTerminalStringFormatter({ color, bold }) {
    let formatter = chalk_1.default;
    if (color && formatter[color]) {
        formatter = formatter[color];
    }
    if (bold) {
        formatter = formatter.bold;
    }
    return formatter;
}
function validateSeverityThreshold(severityThreshold) {
    return common_1.SEVERITIES.map((s) => s.verboseName).indexOf(severityThreshold) > -1;
}
// This is all a copy from Registry snapshots/index
function isVulnFixable(vuln) {
    return vuln.isUpgradable || vuln.isPatchable;
}
function groupVulnerabilities(vulns) {
    return vulns.reduce((map, curr) => {
        if (!map[curr.id]) {
            map[curr.id] = {};
            map[curr.id].list = [];
            map[curr.id].metadata = metadataForVuln(curr);
            map[curr.id].isIgnored = false;
            map[curr.id].isPatched = false;
            // Extra added fields for ease of handling
            map[curr.id].title = curr.title;
            map[curr.id].note = curr.note;
            map[curr.id].severity = curr.severity;
            map[curr.id].isNew = isNewVuln(curr);
            map[curr.id].name = curr.name;
            map[curr.id].version = curr.version;
            map[curr.id].fixedIn = curr.fixedIn;
            map[curr.id].dockerfileInstruction = curr.dockerfileInstruction;
            map[curr.id].dockerBaseImage = curr.dockerBaseImage;
            map[curr.id].nearestFixedInVersion = curr.nearestFixedInVersion;
            map[curr.id].legalInstructions = curr.legalInstructions;
        }
        map[curr.id].list.push(curr);
        if (!map[curr.id].isFixable) {
            map[curr.id].isFixable = isVulnFixable(curr);
        }
        if (!map[curr.id].note) {
            map[curr.id].note = !!curr.note;
        }
        return map;
    }, {});
}
// check if vuln was published in the last month
function isNewVuln(vuln) {
    const MONTH = 30 * 24 * 60 * 60 * 1000;
    const publicationTime = new Date(vuln.publicationTime).getTime();
    return publicationTime > Date.now() - MONTH;
}
function metadataForVuln(vuln) {
    return {
        id: vuln.id,
        title: vuln.title,
        description: vuln.description,
        type: vuln.type,
        name: vuln.name,
        info: vuln.info,
        severity: vuln.severity,
        severityValue: remediation_based_format_issues_1.getSeverityValue(vuln.severity),
        isNew: isNewVuln(vuln),
        version: vuln.version,
        packageManager: vuln.packageManager,
    };
}
module.exports = test;
//# sourceMappingURL=index.js.map