Spaces:
Runtime error
Runtime error
Tales-Cunha commited on
Commit ·
0579f2b
1
Parent(s): 086d1ff
tests: add e2e test for the agent
Browse files- src/agents/tester/index.ts +27 -0
- tests/e2e/poc-generator.test.ts +56 -0
src/agents/tester/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { testerAgent } from "./agent.js";
|
| 2 |
+
import { VulnerabilityReport, PoCResult } from "./types.js";
|
| 3 |
+
|
| 4 |
+
/**
|
| 5 |
+
* Entry point para o Agente Gerador de PoCs.
|
| 6 |
+
* @param report O relatório de vulnerabilidade (mapeado a partir do Finding do Auditor).
|
| 7 |
+
* @returns PoCResult contendo o código do exploit e o status da execução.
|
| 8 |
+
*/
|
| 9 |
+
export async function runPoCGenerator(report: VulnerabilityReport): Promise<PoCResult> {
|
| 10 |
+
console.log(`[runPoCGenerator] Iniciando para: ${report.id} — ${report.title}`);
|
| 11 |
+
|
| 12 |
+
const finalState = await testerAgent.invoke({ report });
|
| 13 |
+
|
| 14 |
+
const result: PoCResult = {
|
| 15 |
+
reportId: report.id,
|
| 16 |
+
status: finalState.status === "running" ? "failed" : finalState.status,
|
| 17 |
+
solidityCode: finalState.pocCode,
|
| 18 |
+
executionLogs: finalState.executionLogs,
|
| 19 |
+
iterations: finalState.iterations,
|
| 20 |
+
};
|
| 21 |
+
|
| 22 |
+
console.log(`[runPoCGenerator] Concluído — status=${result.status}, iterações=${result.iterations}`);
|
| 23 |
+
return result;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
export type { VulnerabilityReport, PoCResult, Finding, OracleContext } from "./types.js";
|
| 27 |
+
export { testerAgent } from "./agent.js";
|
tests/e2e/poc-generator.test.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { runPoCGenerator } from "../../src/agents/tester/index.js";
|
| 2 |
+
import { VulnerabilityReport } from "../../src/agents/tester/types.js";
|
| 3 |
+
|
| 4 |
+
const VULNERABLE_BANK = `
|
| 5 |
+
pragma solidity ^0.8.20;
|
| 6 |
+
contract VulnerableBank {
|
| 7 |
+
mapping(address => uint) public balances;
|
| 8 |
+
function deposit() external payable { balances[msg.sender] += msg.value; }
|
| 9 |
+
function withdraw() external {
|
| 10 |
+
uint amount = balances[msg.sender];
|
| 11 |
+
(bool ok,) = msg.sender.call{value: amount}("");
|
| 12 |
+
require(ok);
|
| 13 |
+
balances[msg.sender] = 0; // atualiza DEPOIS — reentrancy
|
| 14 |
+
}
|
| 15 |
+
receive() external payable {}
|
| 16 |
+
}`.trim();
|
| 17 |
+
|
| 18 |
+
const mockReport: VulnerabilityReport = {
|
| 19 |
+
id: "e2e-reentrancy-001",
|
| 20 |
+
severity: "high",
|
| 21 |
+
type: "reentrancy",
|
| 22 |
+
title: "Reentrancy em withdraw()",
|
| 23 |
+
description: "withdraw() envia ETH antes de zerar o saldo, permitindo re-entrada.",
|
| 24 |
+
affectedContract: { name: "VulnerableBank", sourceCode: VULNERABLE_BANK },
|
| 25 |
+
attackVector: "Contrato atacante com fallback() que chama withdraw() novamente antes do saldo ser zerado.",
|
| 26 |
+
suggestedCheatcodes: ["vm.deal", "vm.startPrank", "vm.stopPrank"],
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
async function runE2ETest() {
|
| 30 |
+
console.log("Iniciando smoke test end-to-end (Reentrancy)...");
|
| 31 |
+
|
| 32 |
+
// Garantir que o sandbox está limpo
|
| 33 |
+
// No mundo real, scripts/setup-sandbox.sh deve ser rodado uma vez no setup do sistema
|
| 34 |
+
|
| 35 |
+
try {
|
| 36 |
+
const result = await runPoCGenerator(mockReport);
|
| 37 |
+
|
| 38 |
+
console.log("\n======= E2E RESULT =======");
|
| 39 |
+
console.log(`Status: ${result.status}`);
|
| 40 |
+
console.log(`Iterações: ${result.iterations}`);
|
| 41 |
+
console.log(`Logs: ${result.executionLogs.length} entrada(s)`);
|
| 42 |
+
|
| 43 |
+
console.assert(result.status === "success", `FALHOU: status esperado 'success', recebido '${result.status}'`);
|
| 44 |
+
console.assert(result.solidityCode.includes("test_Exploit"), "FALHOU: código não contém test_Exploit");
|
| 45 |
+
|
| 46 |
+
if (result.status === "success") {
|
| 47 |
+
console.log("\nSmoke test PASSOU: Vulnerabilidade confirmada via PoC!");
|
| 48 |
+
} else {
|
| 49 |
+
console.error("\nSmoke test FALHOU: Agente não conseguiu gerar PoC válido.");
|
| 50 |
+
}
|
| 51 |
+
} catch (error) {
|
| 52 |
+
console.error("Erro fatal no teste E2E:", error);
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
runE2ETest().catch(console.error);
|