Uanderson Silva commited on
Commit
01d948e
·
1 Parent(s): 7fb9975

lint and use logger

Browse files
src/agents/tester/nodes/context.ts CHANGED
@@ -1,10 +1,11 @@
1
  import fs from "fs/promises";
2
  import path from "path";
 
3
  import { PoCState } from "../state.js";
4
  import { logger } from "../../../logger.js";
5
 
6
  export async function contextNode(state: PoCState): Promise<Partial<PoCState>> {
7
- console.log("[contextNode] Preparando ambiente de testes para:", state.report.title);
8
 
9
  if (state.report.customSandboxDir) {
10
  try {
@@ -18,16 +19,16 @@ export async function contextNode(state: PoCState): Promise<Partial<PoCState>> {
18
  }
19
  }
20
  if (removed > 0) {
21
- console.log(`[contextNode] Limpos ${removed} arquivos de teste antigos.`);
22
  }
23
  } catch (e) {
24
- console.warn("[contextNode] falha na limpeza do diretório de testes:", (e as Error).message);
25
  }
26
  }
27
 
28
- return {
29
- templateCode: "",
30
- pocCode: "",
31
- infrastructurePhase: false
32
  };
33
  }
 
1
  import fs from "fs/promises";
2
  import path from "path";
3
+
4
  import { PoCState } from "../state.js";
5
  import { logger } from "../../../logger.js";
6
 
7
  export async function contextNode(state: PoCState): Promise<Partial<PoCState>> {
8
+ logger.info(`[Tester] contextNode: Preparando ambiente de testes para: ${state.report.title}`);
9
 
10
  if (state.report.customSandboxDir) {
11
  try {
 
19
  }
20
  }
21
  if (removed > 0) {
22
+ logger.info(`[Tester] contextNode: Limpos ${removed} arquivos de teste antigos.`);
23
  }
24
  } catch (e) {
25
+ logger.warn(`[Tester] contextNode: falha na limpeza do diretório de testes: ${(e as Error).message}`);
26
  }
27
  }
28
 
29
+ return {
30
+ templateCode: "",
31
+ pocCode: "",
32
+ infrastructurePhase: false,
33
  };
34
  }
src/agents/tester/nodes/pocoAgent.ts CHANGED
@@ -2,7 +2,7 @@ import { HumanMessage, SystemMessage, AIMessage, trimMessages } from "@langchain
2
  import { PoCState } from "../state.js";
3
  import { pocoTools } from "../tools.js";
4
  import { createLLM } from "../../../config/llm.js";
5
- import { emitStep } from "../../../logger.js";
6
 
7
  const MAX_STEPS = 30; // Max tool calls threshold
8
  const MAX_COST_USD = 3.0; // Max cost threshold
@@ -67,63 +67,66 @@ export async function pocoAgentNode(state: PoCState): Promise<Partial<PoCState>>
67
  const sandboxDir = state.report.customSandboxDir || process.cwd();
68
  const targetFile = state.report.affectedContract.sourceFilePath || state.report.affectedContract.name;
69
  const desc = state.report.description || state.report.title;
70
-
71
  // Original PoCo prompt
72
  const taskPrompt = `Create a vulnerability exposing PoC forge test for the vulnerable contract at ${targetFile} using the vulnerability description: ${desc}. Use the write_file tool to save your PoC code to test/Exploit.t.sol. Write ONLY the test file, test ONLY the described vulnerability, and do NOT modify the original contract. Iterate on compilation, test, and logical errors using the smart_contract_compile and smart_contract_test tools. You are done when the test compiles and successfully demonstrates the vulnerability through passing assertions. Note: your execution sandbox is ${sandboxDir}. Ensure all commands target this directory.`;
73
 
74
- initialMessages = [
75
- new SystemMessage(POCO_SYSTEM_PROMPT),
76
- new HumanMessage(taskPrompt)
77
- ];
78
  messages = initialMessages;
79
  }
80
 
81
  // Invoke model
82
- console.log(`[pocoAgent] Invoking model (Steps: ${state.toolCallCount}/${MAX_STEPS}, Cost: $${state.totalCost.toFixed(2)})...`);
83
- let response;
 
 
84
  let runCost = 0;
85
-
86
  let attempts = 0;
87
  while (attempts < 3) {
88
  try {
89
  const trimmedMessages = await trimMessages(messages, {
90
  maxTokens: 100000,
91
  strategy: "last",
92
- tokenCounter: (msgs) => msgs.map(m => m.content ? m.content.toString().length / 4 : 0).reduce((a, b) => a + b, 0),
 
93
  includeSystem: true,
94
  allowPartial: false,
95
  });
96
 
97
  response = await model.invoke(trimmedMessages, {
98
- configurable: { sandboxDir: state.report.customSandboxDir || process.cwd() }
99
  });
100
-
101
  if (process.env.DEBUG_CONTEXT === "true") {
102
- console.log(`\n--- Agent Response [Step ${state.toolCallCount}] ---`);
103
- console.log(response.content);
104
  if (response.tool_calls) {
105
- console.log("Tool Calls:", JSON.stringify(response.tool_calls, null, 2));
106
  }
107
  }
108
-
109
  // Calculate costs
110
  if (response.response_metadata?.tokenUsage) {
111
  const usage: any = response.response_metadata.tokenUsage;
112
- runCost = calculateCost(usage.promptTokens || usage.input_tokens || usage.prompt_tokens || 0, usage.completionTokens || usage.output_tokens || usage.completion_tokens || 0);
 
 
 
113
  }
114
  break; // Success, exit retry loop
115
  } catch (err: any) {
116
  attempts++;
117
- console.log(`[pocoAgent] API Error (attempt ${attempts}): ${err.message}`);
118
  if (attempts >= 3) {
119
  return {
120
  messages: [new HumanMessage(`Model API Error after 3 attempts: ${err.message}.`)],
121
  status: "failed",
122
- lastError: err.message
123
  };
124
  }
125
  // Wait 10 seconds before retrying (in case of strict rate limits)
126
- await new Promise(r => setTimeout(r, 10000));
127
  }
128
  }
129
 
 
2
  import { PoCState } from "../state.js";
3
  import { pocoTools } from "../tools.js";
4
  import { createLLM } from "../../../config/llm.js";
5
+ import { logger, emitStep } from "../../../logger.js";
6
 
7
  const MAX_STEPS = 30; // Max tool calls threshold
8
  const MAX_COST_USD = 3.0; // Max cost threshold
 
67
  const sandboxDir = state.report.customSandboxDir || process.cwd();
68
  const targetFile = state.report.affectedContract.sourceFilePath || state.report.affectedContract.name;
69
  const desc = state.report.description || state.report.title;
70
+
71
  // Original PoCo prompt
72
  const taskPrompt = `Create a vulnerability exposing PoC forge test for the vulnerable contract at ${targetFile} using the vulnerability description: ${desc}. Use the write_file tool to save your PoC code to test/Exploit.t.sol. Write ONLY the test file, test ONLY the described vulnerability, and do NOT modify the original contract. Iterate on compilation, test, and logical errors using the smart_contract_compile and smart_contract_test tools. You are done when the test compiles and successfully demonstrates the vulnerability through passing assertions. Note: your execution sandbox is ${sandboxDir}. Ensure all commands target this directory.`;
73
 
74
+ initialMessages = [new SystemMessage(POCO_SYSTEM_PROMPT), new HumanMessage(taskPrompt)];
 
 
 
75
  messages = initialMessages;
76
  }
77
 
78
  // Invoke model
79
+ logger.info(
80
+ `[Tester] pocoAgent: Invoking model (Steps: ${state.toolCallCount}/${MAX_STEPS}, Cost: $${state.totalCost.toFixed(2)})...`,
81
+ );
82
+ let response: any;
83
  let runCost = 0;
84
+
85
  let attempts = 0;
86
  while (attempts < 3) {
87
  try {
88
  const trimmedMessages = await trimMessages(messages, {
89
  maxTokens: 100000,
90
  strategy: "last",
91
+ tokenCounter: (msgs) =>
92
+ msgs.map((m) => (m.content ? m.content.toString().length / 4 : 0)).reduce((a, b) => a + b, 0),
93
  includeSystem: true,
94
  allowPartial: false,
95
  });
96
 
97
  response = await model.invoke(trimmedMessages, {
98
+ configurable: { sandboxDir: state.report.customSandboxDir || process.cwd() },
99
  });
100
+
101
  if (process.env.DEBUG_CONTEXT === "true") {
102
+ logger.debug(`[Tester]\n--- Agent Response [Step ${state.toolCallCount}] ---`);
103
+ logger.debug(response.content);
104
  if (response.tool_calls) {
105
+ logger.debug(`[Tester] Tool Calls: ${JSON.stringify(response.tool_calls, null, 2)}`);
106
  }
107
  }
108
+
109
  // Calculate costs
110
  if (response.response_metadata?.tokenUsage) {
111
  const usage: any = response.response_metadata.tokenUsage;
112
+ runCost = calculateCost(
113
+ usage.promptTokens || usage.input_tokens || usage.prompt_tokens || 0,
114
+ usage.completionTokens || usage.output_tokens || usage.completion_tokens || 0,
115
+ );
116
  }
117
  break; // Success, exit retry loop
118
  } catch (err: any) {
119
  attempts++;
120
+ logger.warn(`[Tester] pocoAgent: API Error (attempt ${attempts}): ${err.message}`);
121
  if (attempts >= 3) {
122
  return {
123
  messages: [new HumanMessage(`Model API Error after 3 attempts: ${err.message}.`)],
124
  status: "failed",
125
+ lastError: err.message,
126
  };
127
  }
128
  // Wait 10 seconds before retrying (in case of strict rate limits)
129
+ await new Promise((r) => setTimeout(r, 10000));
130
  }
131
  }
132
 
src/agents/tester/tools/foundryRunner.ts CHANGED
@@ -3,7 +3,9 @@ import { promisify } from "util";
3
  import { writeFile, access } from "fs/promises";
4
  import { join } from "path";
5
 
6
- const execAsync = promisify(exec);
 
 
7
  const DEFAULT_SANDBOX = process.env.SANDBOX_DIR || "/tmp/poc-sandbox";
8
  const TIMEOUT_MS = 60_000;
9
 
@@ -22,7 +24,7 @@ async function ensureSandbox(sandboxDir: string) {
22
  try {
23
  await access(join(sandboxDir, "foundry.toml"));
24
  } catch {
25
- console.log(`[foundryRunner] Sandbox em ${sandboxDir} não encontrado. Inicializando...`);
26
  // Caminho absoluto para o script de setup (assume execução da raiz do projeto)
27
  await execAsync("./scripts/setup-sandbox.sh", { env: { ...process.env, SANDBOX_DIR: sandboxDir } });
28
  }
@@ -30,7 +32,7 @@ async function ensureSandbox(sandboxDir: string) {
30
 
31
  export async function runFoundry(solidityCode: string, sandboxDir: string = DEFAULT_SANDBOX): Promise<FoundryResult> {
32
  await ensureSandbox(sandboxDir);
33
-
34
  // Ensure test directory exists
35
  const testDir = join(sandboxDir, "test");
36
  try {
@@ -38,20 +40,17 @@ export async function runFoundry(solidityCode: string, sandboxDir: string = DEFA
38
  } catch {
39
  await execAsync(`mkdir -p "${testDir}"`);
40
  }
41
-
42
  // Escrever o arquivo no sandbox
43
  const testPath = join(testDir, "Exploit.t.sol");
44
  await writeFile(testPath, solidityCode, "utf-8");
45
 
46
  try {
47
- const { stdout, stderr } = await execAsync(
48
- "forge test --match-contract ExploitTest -vvvv",
49
- {
50
- cwd: sandboxDir,
51
- timeout: TIMEOUT_MS,
52
- env: { ...process.env, PATH: `${process.env.HOME}/.foundry/bin:${process.env.PATH}` }
53
- }
54
- );
55
  return {
56
  exitCode: 0,
57
  stdout,
 
3
  import { writeFile, access } from "fs/promises";
4
  import { join } from "path";
5
 
6
+ import { logger } from "../../../logger.ts";
7
+
8
+ const execAsync = promisify(exec);
9
  const DEFAULT_SANDBOX = process.env.SANDBOX_DIR || "/tmp/poc-sandbox";
10
  const TIMEOUT_MS = 60_000;
11
 
 
24
  try {
25
  await access(join(sandboxDir, "foundry.toml"));
26
  } catch {
27
+ logger.info(`[Tester] foundryRunner: Sandbox em ${sandboxDir} não encontrado. Inicializando...`);
28
  // Caminho absoluto para o script de setup (assume execução da raiz do projeto)
29
  await execAsync("./scripts/setup-sandbox.sh", { env: { ...process.env, SANDBOX_DIR: sandboxDir } });
30
  }
 
32
 
33
  export async function runFoundry(solidityCode: string, sandboxDir: string = DEFAULT_SANDBOX): Promise<FoundryResult> {
34
  await ensureSandbox(sandboxDir);
35
+
36
  // Ensure test directory exists
37
  const testDir = join(sandboxDir, "test");
38
  try {
 
40
  } catch {
41
  await execAsync(`mkdir -p "${testDir}"`);
42
  }
43
+
44
  // Escrever o arquivo no sandbox
45
  const testPath = join(testDir, "Exploit.t.sol");
46
  await writeFile(testPath, solidityCode, "utf-8");
47
 
48
  try {
49
+ const { stdout, stderr } = await execAsync("forge test --match-contract ExploitTest -vvvv", {
50
+ cwd: sandboxDir,
51
+ timeout: TIMEOUT_MS,
52
+ env: { ...process.env, PATH: `${process.env.HOME}/.foundry/bin:${process.env.PATH}` },
53
+ });
 
 
 
54
  return {
55
  exitCode: 0,
56
  stdout,