import { messages } from '../../../core/messages/index.js';
import { splitLines } from '../../../shared/helpers/index.js';
import { criarOcorrencia } from '../../../types/index.js';
import { isOrgVerificada } from './org-verified.js';
const CVES_CONHECIDOS = [{
        action: 'actions/checkout',
        versions: '<v3',
        cve: 'CVE-2022-32197',
        descricao: 'Checkout v1/v2 não valida refs de pull request de forks',
        severidade: 'alta',
        fix: 'Atualizar para actions/checkout@v4'
    }, {
        action: 'actions/upload-artifact',
        versions: '<v4',
        cve: 'CVE-2023-34941',
        descricao: 'Upload de artifacts sem checksum pode permitir adulteração',
        severidade: 'media',
        fix: 'Atualizar para actions/upload-artifact@v4'
    }, {
        action: 'actions/download-artifact',
        versions: '<v4',
        cve: 'CVE-2023-34941',
        descricao: 'Download de artifacts sem verificação de integridade',
        severidade: 'media',
        fix: 'Atualizar para actions/download-artifact@v4'
    }, {
        action: 'actions/cache',
        versions: '<v4',
        descricao: 'Cache v1/v2/v3 com risco de restauração de conteúdo inesperado',
        cve: 'CVE-2023-22490',
        severidade: 'baixa',
        fix: 'Atualizar para actions/cache@v4'
    }, {
        action: 'actions/setup-node',
        versions: '<v4',
        cve: 'CVE-2023-32471',
        descricao: 'setup-node v1-v3 pode injetar conteúdo no GITHUB_STATE',
        severidade: 'media',
        fix: 'Atualizar para actions/setup-node@v4'
    }, {
        action: 'docker/login-action',
        versions: '<v3',
        cve: 'CVE-2023-29017',
        descricao: 'login-action v2 loga argumentos do Docker incluindo tokens',
        severidade: 'alta',
        fix: 'Atualizar para docker/login-action@v3'
    }, {
        action: 'docker/build-push-action',
        versions: '<v5',
        cve: 'CVE-2023-34941',
        descricao: 'Build sem proveniência verificável',
        severidade: 'media',
        fix: 'Atualizar para docker/build-push-action@v5'
    }, {
        action: 'actions/setup-python',
        versions: '<v5',
        cve: 'CVE-2023-39446',
        descricao: 'setup-python v4 não sanitiza variáveis de ambiente',
        severidade: 'baixa',
        fix: 'Atualizar para actions/setup-python@v5'
    }];
const FORK_SUSPEITO_PATTERNS = [/^[a-zA-Z0-9-]+\/[a-zA-Z0-9-]+@[a-f0-9]{40}$/,
    /^[a-zA-Z0-9-]+-[a-zA-Z0-9-]+-[a-zA-Z0-9-]+@/
];
const VERSOES_VULNERAVEIS_NPM = {
    'serialize-javascript': {
        vulneravel: '<6.0.0',
        fix: 'Atualizar para serialize-javascript@>=6.0.0'
    },
    'node-fetch': {
        vulneravel: '<2.6.7',
        fix: 'Atualizar para node-fetch@>=2.6.7'
    },
    'tar': {
        vulneravel: '<6.1.11',
        fix: 'Atualizar para tar@>=6.1.11'
    },
    'minimist': {
        vulneravel: '<1.2.6',
        fix: 'Atualizar para minimist@>=1.2.6'
    },
    'lodash': {
        vulneravel: '<4.17.21',
        fix: 'Atualizar para lodash@>=4.17.21'
    },
    'yaml': {
        vulneravel: '<2.0.0',
        fix: 'Atualizar para yaml@>=2.0.0'
    }
};
function verificarActionVulneravel(uses, linha, relPath) {
    const match = uses.match(/^([a-zA-Z0-9-]+\/[a-zA-Z0-9-]+)@(.+)$/);
    if (!match)
        return null;
    const [, actionRef, version] = match;
    for (const cve of CVES_CONHECIDOS) {
        if (actionRef === cve.action) {
            const versaoNum = parseInt(version.replace(/^v/, ''), 10);
            const maxVersao = parseInt(cve.versions.replace(/^<v/, ''), 10);
            if (!isNaN(versaoNum) && !isNaN(maxVersao) && versaoNum < maxVersao) {
                return criarOcorrencia({
                    tipo: 'dependencia-vulneravel',
                    nivel: cve.severidade === 'alta' ? 'erro' : cve.severidade === 'media' ? 'aviso' : 'info',
                    mensagem: `${actionRef}@${version}: ${cve.descricao} (${cve.cve})`,
                    relPath,
                    linha,
                    sugestao: cve.fix
                });
            }
        }
    }
    if (!isOrgVerificada(actionRef)) {
        for (const pattern of FORK_SUSPEITO_PATTERNS) {
            if (pattern.test(uses)) {
                return criarOcorrencia({
                    tipo: 'fork-suspeito',
                    nivel: 'aviso',
                    mensagem: messages.AnalistaGithubActionsMensagens.suspiciousActionDetected(uses),
                    relPath,
                    linha,
                    sugestao: messages.AnalistaGithubActionsMensagens.suspiciousActionDetectedSugestao
                });
            }
        }
    }
    return null;
}
function verificarDependenciasNpm(runCommand, linha, relPath) {
    for (const [dep, info] of Object.entries(VERSOES_VULNERAVEIS_NPM)) {
        if (new RegExp(`${dep}@?[\\s'\"<>=]`).test(runCommand)) {
            if (runCommand.includes(`npm install ${dep}`) || runCommand.includes(`npm i ${dep}`)) {
                return criarOcorrencia({
                    tipo: 'dependencia-npm-vulneravel',
                    nivel: 'info',
                    mensagem: messages.AnalistaGithubActionsMensagens.possibleVulnerableNpmDependency(dep),
                    relPath,
                    linha,
                    sugestao: info.fix
                });
            }
            const versionMatch = runCommand.match(new RegExp(`${dep}@([\\d^~<>]+)`));
            if (versionMatch) {
                return criarOcorrencia({
                    tipo: 'dependencia-npm-vulneravel',
                    nivel: 'aviso',
                    mensagem: `${dep}@${versionMatch[1]} pode conter vulnerabilidades conhecidas`,
                    relPath,
                    linha,
                    sugestao: info.fix
                });
            }
        }
    }
    return null;
}
export const detectorDependenciasVulneraveis = {
    nome: 'detector-dependencias-vulneraveis',
    categoria: 'workflows',
    descricao: 'Detecta dependências vulneráveis em GitHub Actions',
    test: (relPath) => /\.github\/workflows\/.*\.ya?ml$/i.test(relPath),
    aplicar: (src, relPath) => {
        if (!src)
            return [];
        const ocorrencias = [];
        const linhas = splitLines(src);
        for (let indice = 0; indice < linhas.length; indice++) {
            const linha = linhas[indice];
            const numeroLinha = indice + 1;
            const usesMatch = linha.match(/uses:\s*([a-zA-Z0-9-]+\/[a-zA-Z0-9-]+@[\w.]+)/);
            if (usesMatch) {
                const ocorrencia = verificarActionVulneravel(usesMatch[1], numeroLinha, relPath);
                if (ocorrencia) {
                    ocorrencias.push(ocorrencia);
                }
            }
            if (linha.match(/run:\s*['"]?npm/)) {
                const npmOcorrencia = verificarDependenciasNpm(linha, numeroLinha, relPath);
                if (npmOcorrencia) {
                    ocorrencias.push(npmOcorrencia);
                }
            }
        }
        const hasInstallStep = /npm\s+(install|i\b)|yarn\s+install|pnpm\s+install/i.test(src);
        const hasAuditStep = /\b(npm\s+audit|yarn\s+audit|pnpm\s+audit|snyk|trivy)\b/i.test(src);
        if (hasInstallStep && !hasAuditStep) {
            ocorrencias.push(criarOcorrencia({
                tipo: 'workflow-sem-audit',
                nivel: 'info',
                mensagem: messages.AnalistaGithubActionsMensagens.workflowInstallsDepsWithoutAudit,
                relPath,
                linha: 1,
                sugestao: messages.AnalistaGithubActionsMensagens.workflowInstallsDepsWithoutAuditSugestao
            }));
        }
        const isReleaseOrDeployWorkflow = /release|deploy|publish|tag|changelog/i.test(src);
        const checkoutsWithoutPersistFalse = [];
        for (let indice = 0; indice < linhas.length; indice++) {
            if (/uses:\s*actions\/checkout/.test(linhas[indice])) {
                const proximasLinhas = linhas.slice(indice, Math.min(indice + 10, linhas.length)).join('\n');
                if (!/persist-credentials:\s*false/.test(proximasLinhas)) {
                    checkoutsWithoutPersistFalse.push(indice + 1);
                }
            }
        }
        if (checkoutsWithoutPersistFalse.length > 0 && !isReleaseOrDeployWorkflow) {
            ocorrencias.push(criarOcorrencia({
                tipo: 'checkout-sem-persist-credentials-false',
                nivel: 'info',
                mensagem: messages.AnalistaGithubActionsMensagens.checkoutsWithoutPersistCredentials(checkoutsWithoutPersistFalse.length),
                relPath,
                linha: checkoutsWithoutPersistFalse[0],
                sugestao: messages.AnalistaGithubActionsMensagens.checkoutsWithoutPersistCredentialsSugestao
            }));
        }
        return ocorrencias;
    }
};
//# sourceMappingURL=detector-dependencies-vulnerable.js.map