"use strict";
/**
 * CyberRedTeamAgent Implementation
 *
 * An offensive security sub-agent that performs agentic probing for zero-day
 * vulnerabilities and business logic flaws. Unlike traditional security scanners,
 * this agent generates exploit hypotheses and reproduction scenarios.
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CyberRedTeamAgent = void 0;
const AICore_1 = require("../../core/ai/AICore");
const subAgentPersonalities_1 = require("../../constants/subAgentPersonalities");
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const chalk_1 = __importDefault(require("chalk"));
const MAX_PROBE_CHARS = 2000;
const PROBE_OVERLAP = 400;
const MAX_CHUNKS_PER_FILE = 10;
const CONCURRENCY_LIMIT = 3;
const PROBE_DELAY_MS = 500; // Reduced for performance
class CyberRedTeamAgent {
    constructor() {
        this.name = "CyberRedTeamAgent";
        this.description = "Offensive security specialist that proactively probes for zero-day vulnerabilities and business logic flaws.";
        this.probedHashes = {}; // filePath -> hash
        const personality = (0, subAgentPersonalities_1.getSubAgentPersonality)("CyberRedTeamAgent");
        if (!personality) {
            throw new Error(`Personality not found for CyberRedTeamAgent`);
        }
        this.personality = personality.systemPrompt;
        this.llmProvider = personality.llmProvider;
        this.expertise = personality.expertise;
        this.ai = AICore_1.AICore.getInstance();
        this.cachePath = path.join(process.cwd(), ".mycontext", "cache", "security_probes.json");
        this.loadCacheSync();
    }
    loadCacheSync() {
        try {
            if (fs.pathExistsSync(this.cachePath)) {
                this.probedHashes = fs.readJsonSync(this.cachePath);
            }
        }
        catch { }
    }
    async saveCache() {
        try {
            await fs.ensureDir(path.dirname(this.cachePath));
            await fs.writeJson(this.cachePath, this.probedHashes);
        }
        catch { }
    }
    async getFileHash(content) {
        const crypto = await Promise.resolve().then(() => __importStar(require("crypto")));
        return crypto.createHash("md5").update(content).digest("hex");
    }
    /**
     * Run the probing workflow on target files
     */
    async run(input) {
        const { targetFiles } = input;
        const context = input.context || {};
        const vulnerabilities = [];
        for (const filePath of targetFiles) {
            try {
                const fullPath = filePath;
                if (!(await fs.pathExists(fullPath)))
                    continue;
                if (CyberRedTeamAgent.quotaExhausted) {
                    console.log(chalk_1.default.red(`[CyberRedTeam] Quota exhausted for the day. Skipping ${filePath}...`));
                    continue;
                }
                const content = await fs.readFile(fullPath, "utf-8");
                const currentHash = await this.getFileHash(content);
                if (this.probedHashes[filePath] === currentHash) {
                    console.log(chalk_1.default.gray(`[CyberRedTeam] No changes detected in ${filePath}. Skipping probe...`));
                    continue;
                }
                if (content.length <= MAX_PROBE_CHARS) {
                    const analysis = await this.probeFile(filePath, content, context);
                    vulnerabilities.push(...analysis);
                }
                else {
                    // Implement Rolling Window for large files
                    console.log(chalk_1.default.cyan(`[CyberRedTeam] Large file detected: ${filePath} (${content.length} chars). Using rolling window...`));
                    const fileChunks = this.chunkFileContent(content);
                    const chunkVulnerabilities = [];
                    // Process chunks sequentially
                    let i = 0;
                    for (const chunk of fileChunks) {
                        if (CyberRedTeamAgent.quotaExhausted) {
                            console.log(chalk_1.default.red(`[CyberRedTeam] Aborting remaining chunks of ${filePath} due to quota exhaustion.`));
                            break;
                        }
                        console.log(chalk_1.default.dim(`  [Chunk ${i + 1}/${fileChunks.length}] Probing file segment...`));
                        const result = await this.probeFile(filePath, chunk, context, {
                            chunkIndex: i,
                            totalChunks: fileChunks.length
                        });
                        chunkVulnerabilities.push(...result);
                        // Explicit delay between chunks
                        if (i < fileChunks.length - 1) {
                            await new Promise(resolve => setTimeout(resolve, PROBE_DELAY_MS));
                        }
                        i++;
                    }
                    // Deduplicate across overlaps
                    const deduped = this.deduplicateVulnerabilities(chunkVulnerabilities);
                    vulnerabilities.push(...deduped);
                }
                // Only cache if we didn't hit a quota error in the middle
                if (!CyberRedTeamAgent.quotaExhausted) {
                    const finalHash = await this.getFileHash(content);
                    this.probedHashes[filePath] = finalHash;
                    await this.saveCache();
                }
            }
            catch (error) {
                console.error(chalk_1.default.red(`[CyberRedTeam] Failed to probe file ${filePath}:`), error);
            }
        }
        return { vulnerabilities };
    }
    /**
     * Perform an offensive probe on a specific file content
     */
    async probeFile(filePath, content, context, chunkInfo) {
        if (CyberRedTeamAgent.quotaExhausted)
            return [];
        const chunkHeader = chunkInfo
            ? `\n[NOTE: THIS IS CHUNK ${chunkInfo.chunkIndex + 1} OF ${chunkInfo.totalChunks} OF THE FILE]\n`
            : "";
        // Prune context to absolute bare minimum to save tokens
        const prunedContext = {
            primeObjective: context.primeObjective,
            highLevelArchitecture: context.architecture?.highLevel,
            // Removed features entirely for security probes to avoid token bloat
        };
        const prompt = `
YOU ARE A SECURITY RESILIENCE AUDITOR.${chunkHeader}
File Path: ${filePath}
Project Context (Living Brain): ${JSON.stringify(prunedContext, null, 2)}

Analyze the following code for deep architectural safety risks and resilience gaps. 
Your goal is to identify edge cases, unauthorized access patterns, or logic flaws that could compromise system integrity.
Favor high-impact structural risks over trivial linting issues.

Look for:
1. Business Logic Gaps: Bypassing validations, premature state transitions, privilege boundary issues.
2. Boundary Resilience: Potential for data leakage across context boundaries.
3. Concurrency Safety: Potential for inconsistent states during asynchronous operations.
4. Input Handling: Advanced injection points reaching sensitive sinks.

CODE TO AUDIT:
\`\`\`
${content}
\`\`\`

HYPOTHESIS GENERATION:
Think like a resilience engineer. How could this fail under stress or unauthorized interaction? 
Chain subtle issues if needed.

SCHEMA FOR RESPONSE:
You must return a list of vulnerabilities with risk scenarios and verification steps.
IMPORTANT: Return ONLY valid, raw JSON. Do NOT wrap the response in markdown code blocks.
`;
        const schema = `{
  "vulnerabilities": [
    {
      "type": "string",
      "severity": "low" | "medium" | "high" | "critical",
      "description": "string",
      "exploitScenario": "Detailed step-by-step narrative of the risk trigger",
      "reproSteps": ["string"],
      "reproScript": "A test command or script fragment to verify the gap",
      "location": { "file": "${filePath}", "line": "number?" }
    }
  ]
}`;
        try {
            const result = await this.ai.generateStructuredText(prompt, schema, { temperature: 0.2 });
            return result.vulnerabilities || [];
        }
        catch (error) {
            const errorMessage = error.message || "";
            if (errorMessage.includes("No AI providers available") || errorMessage.includes("exhausted")) {
                console.log(chalk_1.default.red(`\n🛑 [CyberRedTeam] Critical: All AI providers exhausted. Cannot continue audit.`));
                console.log(chalk_1.default.cyan(`💡 TIP: Setup an alternative provider (Gemini, Claude, or OpenAI) in your .env to bypass GitHub's free-tier daily limits.`));
                CyberRedTeamAgent.quotaExhausted = true;
                return [];
            }
            // If a safety filter blocked the chunk, return a placeholder instead of failing the whole run
            if (errorMessage.includes("content management policy") || errorMessage.includes("filtered")) {
                return [{
                        type: "Safety Filter Exception",
                        severity: "low",
                        description: `This code segment in ${filePath} was too sensitive for automated analysis and was skipped by the content safety policy.`,
                        exploitScenario: "Analysis blocked by AI safety policy.",
                        reproSteps: ["Perform manual security review of this specific file chunk."],
                        reproScript: "n/a",
                        location: { file: filePath, line: 1 }
                    }];
            }
            console.warn(chalk_1.default.yellow(`[CyberRedTeam] Failed to get structured reasoning for ${filePath}:`), error);
            return [];
        }
    }
    async validate(input) {
        return Array.isArray(input.targetFiles) && input.targetFiles.length > 0;
    }
    async getStatus() {
        return {
            name: this.name,
            status: "idle",
            errorCount: 0,
            successCount: 0,
        };
    }
    /**
     * Split large content into overlapping chunks
     */
    chunkFileContent(content) {
        const chunks = [];
        let start = 0;
        while (start < content.length && chunks.length < MAX_CHUNKS_PER_FILE) {
            const end = Math.min(start + MAX_PROBE_CHARS, content.length);
            let chunk = content.substring(start, end);
            if (start > 0) {
                chunk = `// ... [PREVIOUS CONTEXT OMITTED]\n${chunk}`;
            }
            if (end < content.length) {
                chunk = `${chunk}\n// ... [SUBSEQUENT CONTEXT OMITTED]`;
            }
            chunks.push(chunk);
            if (end === content.length)
                break;
            start += (MAX_PROBE_CHARS - PROBE_OVERLAP);
        }
        return chunks;
    }
    /**
     * Deduplicate vulnerabilities found across overlapping chunks
     */
    deduplicateVulnerabilities(vulnerabilities) {
        const seen = new Set();
        return vulnerabilities.filter(v => {
            // Create a fuzzy key based on type, line and short description snippet
            const shortDesc = v.description.substring(0, 30).toLowerCase().replace(/\s/g, "");
            const key = `${v.type}|${v.location.line}|${shortDesc}`;
            if (seen.has(key))
                return false;
            seen.add(key);
            return true;
        });
    }
}
exports.CyberRedTeamAgent = CyberRedTeamAgent;
CyberRedTeamAgent.quotaExhausted = false;
//# sourceMappingURL=CyberRedTeamAgent.js.map