import "dotenv/config"; import fs from "fs/promises"; import path from "path"; import { execSync } from "child_process"; import { testerAgent } from "../agents/tester/agent.js"; import { VulnerabilityReport } from "../agents/tester/types.js"; const JSONL_FILE = path.join(process.cwd(), "data", "benchmark_synthetic.jsonl"); const TEMP_DIR = path.join(process.cwd(), "temp_eval_run"); const CSV_FILE = path.join(process.cwd(), "data", "synthetic_evaluation_results.csv"); async function parseJSONL(filepath: string) { const content = await fs.readFile(filepath, "utf8"); return content.split("\n").filter(l => l.trim().length > 0).map(l => JSON.parse(l)); } async function createEmptyFoundryProject(targetDir: string, sourceCode: string, contractName: string) { await fs.mkdir(targetDir, { recursive: true }); execSync("forge init --no-git --force", { cwd: targetDir, env: { ...process.env, PATH: `${process.env.PATH}:/home/tales/.foundry/bin` } }); // Clean up default files await fs.rm(path.join(targetDir, "src", "Counter.sol"), { force: true }); await fs.rm(path.join(targetDir, "test", "Counter.t.sol"), { force: true }); await fs.rm(path.join(targetDir, "script", "Counter.s.sol"), { force: true }); // Write vulnerable contract await fs.writeFile(path.join(targetDir, "src", `${contractName}.sol`), sourceCode); } function appendCsvRow(row: string[]) { const line = row.map(cell => `"${String(cell).replace(/"/g, '""')}"`).join(";") + "\n"; import("fs").then(m => m.appendFileSync(CSV_FILE, line)); } async function runEvaluation() { const cases = await parseJSONL(JSONL_FILE); // Roda a avaliação para os datasets easy e intermediate a pedido do usuário const targetCases = cases.filter(c => c.complexity === "easy" || c.complexity === "intermediate"); console.log(`Iniciando avaliação para ${targetCases.length} projetos sintéticos (easy/intermediate)...`); const csvHeaders = [ "Task_ID", "Complexity", "Time_Sec", "Pass_at_1", "Tool_Calls", "Total_Cost_USD", "Final_Status", "Error_Msg" ]; await fs.mkdir(path.join(process.cwd(), "data"), { recursive: true }); await fs.writeFile(CSV_FILE, csvHeaders.join(";") + "\n"); let totalCost = 0; let passed = 0; for (const c of targetCases) { console.log(`\n\n${"=".repeat(60)}`); console.log(`=== INICIANDO CASO: ${c.task_id} ===`); console.log(`${"=".repeat(60)}`); const startTime = Date.now(); const sandboxDir = path.join(TEMP_DIR, c.repo_name); // Setup Forge const contractName = c.repo_name.replace(/-/g, ""); // Simplified contract name parsing await createEmptyFoundryProject(sandboxDir, c.source_code, contractName); const report: VulnerabilityReport = { id: c.task_id, severity: c.impact || "high", type: c.expected_vulnerability, title: c.task_id, description: c.annotation, affectedContract: { name: contractName, sourceCode: c.source_code, sourceFilePath: `src/${contractName}.sol` }, attackVector: c.expected_vulnerability, customSandboxDir: sandboxDir }; console.log(`[CENÁRIO SINTÉTICO] Gerando exploit para ${c.task_id}...`); const result = await testerAgent.invoke( { report }, { recursionLimit: 100, configurable: { sandboxDir } } ) as any; const timeSec = ((Date.now() - startTime) / 1000).toFixed(1); const passAt1 = result.status === "success"; const toolCalls = result.toolCallCount || 0; const cost = result.totalCost || 0; totalCost += cost; if (passAt1) passed++; console.log(`=> Status: ${result.status} | Tools: ${toolCalls} | Cost: $${cost.toFixed(2)} | Time: ${timeSec}s`); if (!passAt1) { console.log("--- LLM HISTORY ---"); for (const m of result.messages) { console.log(`[${m._getType()}] ${m.content.substring(0, 200)}...`); if (m._getType() === "ai" && m.tool_calls) { console.log("Tool calls:", JSON.stringify(m.tool_calls)); } if (m._getType() === "tool" && m.name === "smart_contract_test") { console.log("Test Output:", m.content); } } console.log("-------------------"); } appendCsvRow([ c.task_id, c.complexity, timeSec, passAt1 ? "TRUE" : "FALSE", toolCalls.toString(), cost.toFixed(4), result.status, result.lastError || "" ]); } console.log(`\n\nAVALIAÇÃO CONCLUÍDA!`); console.log(`Accuracy (Pass@1): ${((passed / targetCases.length) * 100).toFixed(1)}% (${passed}/${targetCases.length})`); console.log(`Total Cost: $${totalCost.toFixed(2)}`); console.log(`Resultados em: ${CSV_FILE}`); } runEvaluation().catch(err => { console.error("Fatal error during evaluation:", err); process.exit(1); });