Tales-Cunha commited on
Commit
6389903
·
1 Parent(s): 69b971b

feat: Implementar `scaffoldGenerator` and Implementar `oracleNode`

Browse files
src/agents/tester/agent.ts CHANGED
@@ -1,9 +1,16 @@
1
  import { StateGraph, END, START } from "@langchain/langgraph";
2
  import { PoCStateAnnotation, PoCState } from "./state.js";
 
 
3
 
4
  async function oracleNode(state: PoCState): Promise<Partial<PoCState>> {
5
- console.log("[oracleNode] stub report recebido:", state.report.id);
6
- return {};
 
 
 
 
 
7
  }
8
 
9
  async function generatePoCNode(state: PoCState): Promise<Partial<PoCState>> {
 
1
  import { StateGraph, END, START } from "@langchain/langgraph";
2
  import { PoCStateAnnotation, PoCState } from "./state.js";
3
+ import { generateLocalScaffold } from "./tools/scaffoldGenerator.js";
4
+ import { OracleContext } from "./types.js";
5
 
6
  async function oracleNode(state: PoCState): Promise<Partial<PoCState>> {
7
+ console.log("[oracleNode] gerando scaffold para:", state.report.title);
8
+
9
+ const solidityScaffold = generateLocalScaffold(state.report);
10
+ const oracleContext: OracleContext = { solidityScaffold };
11
+
12
+ console.log("[oracleNode] scaffold gerado, tamanho:", solidityScaffold.length, "chars");
13
+ return { oracleContext };
14
  }
15
 
16
  async function generatePoCNode(state: PoCState): Promise<Partial<PoCState>> {
src/agents/tester/tools/scaffoldGenerator.ts ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { VulnerabilityReport } from "../types.js";
2
+
3
+ export function generateLocalScaffold(report: VulnerabilityReport): string {
4
+ const cheatcodes = report.suggestedCheatcodes?.join(", ") ?? "vm.deal, vm.prank, vm.warp";
5
+
6
+ return `// SPDX-License-Identifier: UNLICENSED
7
+ pragma solidity ^0.8.20;
8
+
9
+ import "forge-std/Test.sol";
10
+ import "forge-std/console.sol";
11
+
12
+ // ── Código-fonte do contrato vulnerável ──────────────────────────────────────
13
+ ${report.affectedContract.sourceCode}
14
+ // ─────────────────────────────────────────────────────────────────────────────
15
+
16
+ contract ExploitTest is Test {
17
+ ${report.affectedContract.name} target;
18
+ address constant ATTACKER = address(0xBEEF);
19
+
20
+ // setUp() gerado automaticamente pelo Oracle — NÃO MODIFICAR
21
+ function setUp() public {
22
+ target = new ${report.affectedContract.name}();
23
+ vm.deal(address(target), 100 ether);
24
+ vm.deal(ATTACKER, 10 ether);
25
+ vm.label(address(target), "TARGET");
26
+ vm.label(ATTACKER, "ATTACKER");
27
+ }
28
+
29
+ // Vulnerabilidade: ${report.title}
30
+ // Tipo: ${report.type}
31
+ // Vetor: ${report.attackVector}
32
+ ${report.exploitablePaths ? `// Caminhos de Exploração:\n // - ${report.exploitablePaths.join("\n // - ")}` : ""}
33
+ // Cheatcodes sugeridos: ${cheatcodes}
34
+ //
35
+ // COMPLETE APENAS ESTA FUNÇÃO — não altere setUp() nem os campos acima
36
+ function test_Exploit() public {
37
+ vm.startPrank(ATTACKER);
38
+ // TODO: implementar exploit aqui
39
+ vm.stopPrank();
40
+ }
41
+ }`.trim();
42
+ }
src/agents/tester/types.ts CHANGED
@@ -1,3 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  export interface VulnerabilityReport {
2
  id: string;
3
  severity: "critical" | "high" | "medium" | "low";
@@ -10,6 +25,9 @@ export interface VulnerabilityReport {
10
  };
11
  attackVector: string;
12
  suggestedCheatcodes?: string[];
 
 
 
13
  }
14
 
15
  export interface OracleContext {
 
1
+ export interface Finding {
2
+ title: string;
3
+ description: string;
4
+ recommendation: string;
5
+ severity: "high" | "medium" | "low";
6
+ codeSnippet: string;
7
+ location: string;
8
+ path: string;
9
+ judgeReview: {
10
+ review: string;
11
+ confidence: number;
12
+ exploitablePaths: string[];
13
+ };
14
+ }
15
+
16
  export interface VulnerabilityReport {
17
  id: string;
18
  severity: "critical" | "high" | "medium" | "low";
 
25
  };
26
  attackVector: string;
27
  suggestedCheatcodes?: string[];
28
+ codeSnippet?: string;
29
+ location?: string;
30
+ exploitablePaths?: string[];
31
  }
32
 
33
  export interface OracleContext {
src/index.ts CHANGED
@@ -1,9 +1,9 @@
1
  import "dotenv/config";
2
 
3
- import { auditorAgent } from "./agents/auditor/agent.ts";
4
- import { coderAgent } from "./agents/coder/agent.ts";
5
- import { testerAgent } from "./agents/tester/agent.ts";
6
- import type { VulnerabilityReport } from "./agents/tester/types.ts";
7
 
8
  const requirements = ["ERC20 token", "pausable", "ownable"];
9
 
@@ -15,24 +15,38 @@ const auditorResult = await auditorAgent.invoke({ solidityFile: coderResult.cont
15
  console.log("\n======= Auditor =======");
16
  // console.log(auditorResult.vulnerabilities);
17
 
18
- // Mapeamento temporário para satisfazer o novo estado do testerAgent
19
- const mockReport: VulnerabilityReport = {
20
- id: "test-001",
21
- severity: "high",
22
- type: "reentrancy",
23
- title: "Vulnerabilidade Detectada",
24
- description: "Descrição da vulnerabilidade",
25
- affectedContract: {
26
- name: "Contract",
27
- sourceCode: coderResult.contract,
28
- },
29
- attackVector: "Vetor de ataque",
30
- };
31
-
32
- const testerResult = await testerAgent.invoke({
33
- report: mockReport,
34
- });
35
-
36
- console.log("\n======= Tester =======");
37
- console.log("Status:", testerResult.status);
38
- console.log("Iterations:", testerResult.iterations);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import "dotenv/config";
2
 
3
+ import { auditorAgent } from "./agents/auditor/agent.js";
4
+ import { coderAgent } from "./agents/coder/agent.js";
5
+ import { testerAgent } from "./agents/tester/agent.js";
6
+ import type { VulnerabilityReport, Finding } from "./agents/tester/types.js";
7
 
8
  const requirements = ["ERC20 token", "pausable", "ownable"];
9
 
 
15
  console.log("\n======= Auditor =======");
16
  // console.log(auditorResult.vulnerabilities);
17
 
18
+ function mapFindingToReport(finding: Finding, sourceCode: string): VulnerabilityReport {
19
+ // Extract contract name from path (e.g., "contracts/CafeToken.sol" -> "CafeToken")
20
+ const nameMatch = finding.path.match(/([^\/]+)\.sol$/);
21
+ const contractName = nameMatch ? nameMatch[1] : "TargetContract";
22
+
23
+ return {
24
+ id: finding.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 50),
25
+ severity: finding.severity === "high" ? "high" : finding.severity === "medium" ? "medium" : "low",
26
+ type: "custom",
27
+ title: finding.title,
28
+ description: finding.description,
29
+ affectedContract: {
30
+ name: contractName,
31
+ sourceCode: sourceCode,
32
+ },
33
+ attackVector: finding.judgeReview.exploitablePaths[0] || "Unknown vector",
34
+ exploitablePaths: finding.judgeReview.exploitablePaths,
35
+ codeSnippet: finding.codeSnippet,
36
+ location: finding.location
37
+ };
38
+ }
39
+
40
+ if (auditorResult.vulnerabilities.length > 0) {
41
+ const finding = auditorResult.vulnerabilities[0] as Finding;
42
+ const report = mapFindingToReport(finding, coderResult.contract);
43
+
44
+ const testerResult = await testerAgent.invoke({ report });
45
+
46
+ console.log("\n======= Tester =======");
47
+ console.log("Status:", testerResult.status);
48
+ console.log("Iterations:", testerResult.iterations);
49
+ } else {
50
+ console.log("\n======= Tester =======");
51
+ console.log("Nenhuma vulnerabilidade encontrada pelo Auditor.");
52
+ }
tests/scaffold.test.ts ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { generateLocalScaffold } from "../src/agents/tester/tools/scaffoldGenerator.js";
2
+
3
+ const mockReport = {
4
+ id: "t1",
5
+ severity: "high" as const,
6
+ type: "reentrancy",
7
+ title: "Reentrancy in withdraw()",
8
+ description: "withdraw() sends ETH before zeroing balance",
9
+ attackVector: "Malicious callback",
10
+ affectedContract: {
11
+ name: "VulnerableBank",
12
+ sourceCode: `
13
+ pragma solidity ^0.8.20;
14
+ contract VulnerableBank {
15
+ mapping(address=>uint) public balances;
16
+ function withdraw() external {
17
+ uint a = balances[msg.sender];
18
+ (bool ok,) = msg.sender.call{value:a}("");
19
+ require(ok); balances[msg.sender] = 0;
20
+ }
21
+ }`
22
+ }
23
+ };
24
+
25
+ const scaffold = generateLocalScaffold(mockReport);
26
+ console.log("--- Scaffold Output ---");
27
+ console.log(scaffold);
28
+ console.log("--- End Scaffold ---");
29
+
30
+ console.assert(scaffold.includes("contract ExploitTest is Test"), "Scaffold missing ExploitTest");
31
+ console.assert(scaffold.includes("VulnerableBank target"), "Scaffold missing target declaration");
32
+ console.assert(scaffold.includes("function setUp()"), "Scaffold missing setUp");
33
+ console.assert(scaffold.includes("function test_Exploit()"), "Scaffold missing test_Exploit");
34
+
35
+ console.log("Scaffold generator test passed");