"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFixedVersionByDatasource = getFixedVersionByDatasource;
exports.detectVulnerabilityAlerts = detectVulnerabilityAlerts;
const tslib_1 = require("tslib");
const error_messages_1 = require("../../../constants/error-messages");
const logger_1 = require("../../../logger");
const crate_1 = require("../../../modules/datasource/crate");
const go_1 = require("../../../modules/datasource/go");
const maven_1 = require("../../../modules/datasource/maven");
const npm_1 = require("../../../modules/datasource/npm");
const nuget_1 = require("../../../modules/datasource/nuget");
const packagist_1 = require("../../../modules/datasource/packagist");
const pypi_1 = require("../../../modules/datasource/pypi");
const rubygems_1 = require("../../../modules/datasource/rubygems");
const platform_1 = require("../../../modules/platform");
const allVersioning = tslib_1.__importStar(require("../../../modules/versioning"));
const composerVersioning = tslib_1.__importStar(require("../../../modules/versioning/composer"));
const mavenVersioning = tslib_1.__importStar(require("../../../modules/versioning/maven"));
const npmVersioning = tslib_1.__importStar(require("../../../modules/versioning/npm"));
const pep440Versioning = tslib_1.__importStar(require("../../../modules/versioning/pep440"));
const rubyVersioning = tslib_1.__importStar(require("../../../modules/versioning/ruby"));
const semverVersioning = tslib_1.__importStar(require("../../../modules/versioning/semver"));
const markdown_1 = require("../../../util/markdown");
function getFixedVersionByDatasource(fixedVersion, datasource) {
    if (datasource === maven_1.MavenDatasource.id || datasource === nuget_1.NugetDatasource.id) {
        return `[${fixedVersion},)`;
    }
    // crates.io, Go, Hex, npm, RubyGems, PyPI
    return `>= ${fixedVersion}`;
}
// TODO can return `null` and `undefined` (#22198)
async function detectVulnerabilityAlerts(input) {
    if (!input?.vulnerabilityAlerts) {
        return input;
    }
    if (input.vulnerabilityAlerts.enabled === false) {
        logger_1.logger.debug('Vulnerability alerts are disabled');
        return input;
    }
    const alerts = await platform_1.platform.getVulnerabilityAlerts?.();
    if (!alerts?.length) {
        logger_1.logger.debug('No vulnerability alerts found');
        if (input.vulnerabilityAlertsOnly) {
            throw new Error(error_messages_1.NO_VULNERABILITY_ALERTS);
        }
        return input;
    }
    const config = { ...input };
    const versionings = {
        'github-tags': semverVersioning.id,
        go: semverVersioning.id,
        packagist: composerVersioning.id,
        maven: mavenVersioning.id,
        npm: npmVersioning.id,
        nuget: semverVersioning.id,
        pypi: pep440Versioning.id,
        rubygems: rubyVersioning.id,
    };
    const combinedAlerts = {};
    for (const alert of alerts) {
        try {
            if (alert.dismissed_reason) {
                continue;
            }
            if (!alert.security_vulnerability?.first_patched_version) {
                logger_1.logger.debug({ alert }, 'Vulnerability alert has no firstPatchedVersion - skipping');
                continue;
            }
            const datasourceMapping = {
                composer: packagist_1.PackagistDatasource.id,
                go: go_1.GoDatasource.id,
                maven: maven_1.MavenDatasource.id,
                npm: npm_1.NpmDatasource.id,
                nuget: nuget_1.NugetDatasource.id,
                pip: pypi_1.PypiDatasource.id,
                rubygems: rubygems_1.RubygemsDatasource.id,
                rust: crate_1.CrateDatasource.id,
            };
            const datasource = datasourceMapping[alert.security_vulnerability.package.ecosystem];
            const depName = alert.security_vulnerability.package.name;
            const fileName = alert.dependency.manifest_path;
            const fileType = fileName.split('/').pop();
            const firstPatchedVersion = alert.security_vulnerability.first_patched_version.identifier;
            const advisory = alert.security_advisory;
            combinedAlerts[fileName] ||= {};
            combinedAlerts[fileName][datasource] ||= {};
            combinedAlerts[fileName][datasource][depName] ||= {
                advisories: [],
            };
            const alertDetails = combinedAlerts[fileName][datasource][depName];
            alertDetails.advisories.push(advisory);
            const version = allVersioning.get(versionings[datasource]);
            if (version.isVersion(firstPatchedVersion)) {
                if (!alertDetails.firstPatchedVersion ||
                    version.isGreaterThan(firstPatchedVersion, alertDetails.firstPatchedVersion)) {
                    alertDetails.firstPatchedVersion = firstPatchedVersion;
                }
            }
            else {
                logger_1.logger.debug('Invalid firstPatchedVersion: ' + firstPatchedVersion);
            }
            alertDetails.fileType = fileType;
        }
        catch (err) {
            logger_1.logger.warn({ err }, 'Error parsing vulnerability alert');
        }
    }
    const alertPackageRules = [];
    config.remediations = {};
    for (const [fileName, files] of Object.entries(combinedAlerts)) {
        for (const [datasource, dependencies] of Object.entries(files)) {
            for (const [depName, val] of Object.entries(dependencies)) {
                let prBodyNotes = [];
                try {
                    prBodyNotes = ['### GitHub Vulnerability Alerts'].concat(val.advisories.map((advisory) => {
                        const identifiers = advisory.identifiers;
                        const description = advisory.description;
                        let content = '#### ';
                        let heading;
                        if (identifiers.some((id) => id.type === 'CVE')) {
                            heading = identifiers
                                .filter((id) => id.type === 'CVE')
                                .map((id) => id.value)
                                .join(' / ');
                        }
                        else {
                            heading = identifiers.map((id) => id.value).join(' / ');
                        }
                        if (advisory.references?.length) {
                            heading = `[${heading}](${advisory.references[0].url})`;
                        }
                        content += heading;
                        content += '\n\n';
                        content += (0, markdown_1.sanitizeMarkdown)(description);
                        return content;
                    }));
                }
                catch (err) /* istanbul ignore next */ {
                    logger_1.logger.warn({ err }, 'Error generating vulnerability PR notes');
                }
                // TODO: types (#22198)
                const matchFileNames = datasource === go_1.GoDatasource.id
                    ? [fileName.replace('go.sum', 'go.mod')]
                    : [fileName];
                let matchRule = {
                    matchDatasources: [datasource],
                    matchPackageNames: [depName],
                    matchFileNames,
                };
                let matchCurrentVersion = `< ${val.firstPatchedVersion}`;
                if (datasource === maven_1.MavenDatasource.id ||
                    datasource === nuget_1.NugetDatasource.id) {
                    matchCurrentVersion = `(,${val.firstPatchedVersion})`;
                }
                // Remediate only direct dependencies
                matchRule = {
                    ...matchRule,
                    matchCurrentVersion,
                    vulnerabilityFixVersion: val.firstPatchedVersion,
                    prBodyNotes,
                    isVulnerabilityAlert: true,
                    force: {
                        ...config.vulnerabilityAlerts,
                    },
                };
                alertPackageRules.push(matchRule);
            }
        }
    }
    logger_1.logger.debug({ alertPackageRules }, 'alert package rules');
    config.packageRules = (config.packageRules ?? []).concat(alertPackageRules);
    return config;
}
//# sourceMappingURL=vulnerability.js.map