"use strict";
/**
 * Layer 1: Configuration Auditing
 * Scans configuration files for security misconfigurations
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.CONFIG_RULES = void 0;
exports.auditConfiguration = auditConfiguration;
// Configuration audit rules
exports.CONFIG_RULES = [
    // Dockerfile rules
    {
        name: 'Docker running as root',
        filePatterns: ['Dockerfile', '*.dockerfile'],
        check: (content) => {
            const violations = [];
            const lines = content.split('\n');
            // Check if USER instruction exists
            const hasUserInstruction = lines.some(line => line.trim().toUpperCase().startsWith('USER '));
            // Check for explicit root user
            lines.forEach((line, index) => {
                if (line.trim().toUpperCase() === 'USER ROOT') {
                    violations.push({
                        line: index + 1,
                        lineContent: line.trim(),
                        message: 'Container explicitly runs as root user',
                        severity: 'high',
                    });
                }
            });
            // If no USER instruction at all, flag it
            if (!hasUserInstruction && lines.length > 5) {
                violations.push({
                    line: 1,
                    lineContent: 'Dockerfile',
                    message: 'No USER instruction found - container will run as root by default',
                    severity: 'medium',
                });
            }
            return violations;
        },
    },
    {
        name: 'Hardcoded secrets in Docker build args',
        filePatterns: ['Dockerfile', '*.dockerfile', 'docker-compose.yml', 'docker-compose.yaml'],
        check: (content) => {
            const violations = [];
            const lines = content.split('\n');
            // Pattern: ARG/ENV VAR_NAME="value" where value is NOT empty or a variable reference
            // Skip: empty defaults (""), variable expansion ($VAR, ${VAR}), shell variable references
            const sensitiveArgPattern = /ARG\s+\w*(PASSWORD|SECRET|KEY|TOKEN|CREDENTIAL)\w*\s*=\s*["']([^"'$]+)["']/i;
            const sensitiveEnvPattern = /ENV\s+\w*(PASSWORD|SECRET|KEY|TOKEN|CREDENTIAL)\w*\s*=\s*["']([^"'$]+)["']/i;
            const dockerComposePattern = /^\s*(PASSWORD|SECRET|KEY|TOKEN)\s*[:=]\s*["']?([^"'\s${\n]+)/i;
            lines.forEach((line, index) => {
                // Check ARG statements
                const argMatch = line.match(sensitiveArgPattern);
                if (argMatch) {
                    const value = argMatch[2];
                    // Skip if value is empty or looks like a placeholder instruction
                    if (value && value.length > 0 && !/^(changeme|replace|your[_-]|xxx)/i.test(value)) {
                        violations.push({
                            line: index + 1,
                            lineContent: line.trim(),
                            message: 'Hardcoded sensitive value in build argument - use build-time secrets or runtime environment variables',
                            severity: 'medium', // Downgraded from critical - these are defaults that should be overridden
                        });
                    }
                    return;
                }
                // Skip ENV statements that just reference ARG variables (ENV VAR="$VAR")
                if (/ENV\s+\w+\s*=\s*["']\$\w+["']/i.test(line)) {
                    return;
                }
                // Check ENV statements with actual hardcoded values
                const envMatch = line.match(sensitiveEnvPattern);
                if (envMatch) {
                    const value = envMatch[2];
                    if (value && value.length > 0) {
                        violations.push({
                            line: index + 1,
                            lineContent: line.trim(),
                            message: 'Hardcoded sensitive value in environment variable',
                            severity: 'high',
                        });
                    }
                    return;
                }
                // Check docker-compose patterns
                if (dockerComposePattern.test(line)) {
                    const match = line.match(dockerComposePattern);
                    if (match && match[2] && match[2].length > 0) {
                        violations.push({
                            line: index + 1,
                            lineContent: line.trim(),
                            message: 'Hardcoded sensitive value in docker-compose configuration',
                            severity: 'high',
                        });
                    }
                }
            });
            return violations;
        },
    },
    // CORS configuration
    {
        name: 'Permissive CORS configuration',
        filePatterns: ['*.ts', '*.js', '*.tsx', '*.jsx', 'next.config.*', 'vercel.json', '*.yaml', '*.yml'],
        check: (content) => {
            const violations = [];
            const lines = content.split('\n');
            const corsPatterns = [
                /['"]Access-Control-Allow-Origin['"]\s*[,:]\s*['"]\*['"]/i,
                /cors\s*\(\s*\{\s*origin\s*:\s*['"]\*['"]/i,
                /origin\s*:\s*['"]\*['"]/i,
                /allowedOrigins?\s*[=:]\s*\[\s*['"]\*['"]/i,
                /Access-Control-Allow-Origin:\s*\*/i,
            ];
            lines.forEach((line, index) => {
                for (const pattern of corsPatterns) {
                    if (pattern.test(line)) {
                        violations.push({
                            line: index + 1,
                            lineContent: line.trim(),
                            message: 'Permissive CORS policy allows requests from any origin (*)',
                            severity: 'medium',
                        });
                        break;
                    }
                }
            });
            return violations;
        },
    },
    // GitHub Actions secrets exposure
    {
        name: 'GitHub Actions security issues',
        filePatterns: ['.github/workflows/*.yml', '.github/workflows/*.yaml'],
        check: (content) => {
            const violations = [];
            const lines = content.split('\n');
            // Check for pull_request_target with checkout
            const hasPRTarget = content.includes('pull_request_target');
            const hasCheckout = content.includes('actions/checkout');
            if (hasPRTarget && hasCheckout) {
                const checkoutLine = lines.findIndex(l => l.includes('actions/checkout'));
                violations.push({
                    line: checkoutLine + 1,
                    lineContent: lines[checkoutLine]?.trim() || '',
                    message: 'Using actions/checkout with pull_request_target can expose secrets to untrusted code',
                    severity: 'high',
                });
            }
            // Check for hardcoded secrets
            lines.forEach((line, index) => {
                if (/env:\s*\w+\s*=\s*['"][^$]/.test(line) &&
                    /(SECRET|TOKEN|KEY|PASSWORD)/i.test(line)) {
                    violations.push({
                        line: index + 1,
                        lineContent: line.trim(),
                        message: 'Potential hardcoded secret in GitHub Actions workflow',
                        severity: 'critical',
                    });
                }
            });
            return violations;
        },
    },
    // Next.js security config
    {
        name: 'Next.js security configuration',
        filePatterns: ['next.config.js', 'next.config.ts', 'next.config.mjs'],
        check: (content) => {
            const violations = [];
            const lines = content.split('\n');
            // Only flag if poweredByHeader is explicitly set to true (not if missing)
            if (content.includes('poweredByHeader: true') || content.includes('poweredByHeader:true')) {
                const lineIndex = lines.findIndex(l => l.includes('poweredByHeader'));
                violations.push({
                    line: lineIndex >= 0 ? lineIndex + 1 : 1,
                    lineContent: lines[lineIndex]?.trim() || 'poweredByHeader: true',
                    message: 'poweredByHeader is enabled - consider setting to false to hide X-Powered-By header',
                    severity: 'low',
                });
            }
            // Check for exposed source maps in production
            lines.forEach((line, index) => {
                if (/productionBrowserSourceMaps\s*:\s*true/.test(line)) {
                    violations.push({
                        line: index + 1,
                        lineContent: line.trim(),
                        message: 'Production source maps are enabled - this exposes your source code',
                        severity: 'medium',
                    });
                }
            });
            return violations;
        },
    },
    // Package.json security
    {
        name: 'Package.json security issues',
        filePatterns: ['package.json'],
        check: (content) => {
            const violations = [];
            try {
                const pkg = JSON.parse(content);
                // Check for postinstall scripts that could be malicious
                if (pkg.scripts?.postinstall || pkg.scripts?.preinstall) {
                    const lines = content.split('\n');
                    const scriptLine = lines.findIndex(l => l.includes('"postinstall"') || l.includes('"preinstall"'));
                    violations.push({
                        line: scriptLine + 1,
                        lineContent: lines[scriptLine]?.trim() || '',
                        message: 'Pre/post install scripts can execute arbitrary code - review carefully',
                        severity: 'low',
                    });
                }
                // Check for wildcard dependencies
                const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
                const lines = content.split('\n');
                // Get the package's own npm scope to detect internal monorepo deps
                const ownScope = pkg.name?.startsWith('@') ? pkg.name.split('/')[0] : null;
                // Also detect common org scope from other dependencies (for packages without scoped names)
                // If we see @org/foo and @org/bar in deps, @org is likely the monorepo's scope
                const scopeCounts = {};
                for (const depName of Object.keys(allDeps)) {
                    if (depName.startsWith('@')) {
                        const scope = depName.split('/')[0];
                        scopeCounts[scope] = (scopeCounts[scope] || 0) + 1;
                    }
                }
                // Find the most common scope (likely the monorepo's org scope)
                const inferredScope = Object.entries(scopeCounts)
                    .filter(([, count]) => count >= 2) // At least 2 deps from same scope
                    .sort((a, b) => b[1] - a[1])[0]?.[0] || null;
                for (const [name, version] of Object.entries(allDeps)) {
                    if (version === '*' || version === 'latest') {
                        // Skip internal monorepo packages:
                        // 1. Same npm scope as the package itself
                        // 2. Or same scope as other workspace packages (inferred from multiple deps)
                        const depScope = name.startsWith('@') ? name.split('/')[0] : null;
                        // Check if this is a workspace package
                        const isWorkspacePackage = (ownScope && depScope === ownScope) ||
                            (inferredScope && depScope === inferredScope && version === '*');
                        if (isWorkspacePackage) {
                            continue;
                        }
                        const depLine = lines.findIndex(l => l.includes(`"${name}"`));
                        violations.push({
                            line: depLine + 1,
                            lineContent: lines[depLine]?.trim() || '',
                            message: `Dependency "${name}" uses wildcard/latest version - pin to specific version`,
                            severity: 'medium',
                        });
                    }
                }
            }
            catch {
                // Invalid JSON, skip
            }
            return violations;
        },
    },
];
// Check if file matches any of the patterns
function matchesFilePattern(filePath, patterns) {
    const fileName = filePath.split('/').pop() || '';
    return patterns.some(pattern => {
        if (pattern.includes('*')) {
            const regex = new RegExp('^' + pattern.replace(/\*/g, '.*').replace(/\./g, '\\.') + '$', 'i');
            return regex.test(fileName) || regex.test(filePath);
        }
        return fileName === pattern || filePath.endsWith(pattern);
    });
}
function auditConfiguration(content, filePath, options) {
    const vulnerabilities = [];
    for (const rule of exports.CONFIG_RULES) {
        if (matchesFilePattern(filePath, rule.filePatterns)) {
            const violations = rule.check(content, filePath);
            for (const violation of violations) {
                vulnerabilities.push({
                    id: `config-${filePath}-${violation.line}-${rule.name}`,
                    filePath,
                    lineNumber: violation.line,
                    lineContent: violation.lineContent,
                    severity: violation.severity,
                    category: 'insecure_config',
                    title: rule.name,
                    description: violation.message,
                    suggestedFix: getConfigFix(rule.name, violation),
                    confidence: 'high',
                    layer: 1,
                });
            }
        }
    }
    return vulnerabilities;
}
function getConfigFix(ruleName, violation) {
    const fixes = {
        'Docker running as root': 'Add a USER instruction to run as a non-root user: USER node',
        'Hardcoded secrets in Docker build args': 'Use Docker secrets or pass values at runtime via environment variables',
        'Permissive CORS configuration': 'Specify allowed origins explicitly instead of using wildcard (*)',
        'GitHub Actions security issues': 'Use secrets context (${{ secrets.NAME }}) for sensitive values',
        'Next.js security configuration': 'Review Next.js security best practices and configure headers appropriately',
        'Package.json security issues': 'Pin dependencies to specific versions and review install scripts',
    };
    return fixes[ruleName] || 'Review and fix the security configuration';
}
//# sourceMappingURL=config-audit.js.map