Spaces:
Runtime error
Runtime error
File size: 5,634 Bytes
5710d63 2a70ee5 5710d63 3f143e9 2a70ee5 fc99222 5710d63 48c7a9b fc99222 48c7a9b 5710d63 48c7a9b 5710d63 48c7a9b 5710d63 48c7a9b 5710d63 48c7a9b 5710d63 48c7a9b 5710d63 48c7a9b 5710d63 48c7a9b 5710d63 3f143e9 4e2e30e 2a70ee5 3f143e9 48c7a9b 4e2e30e 2a70ee5 d26fc11 3f143e9 2a70ee5 3f143e9 48c7a9b d26fc11 3f143e9 5710d63 48c7a9b 5710d63 48c7a9b fc99222 5710d63 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | import "dotenv/config";
import { mkdirSync, writeFileSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
import { tmpdir } from "node:os";
import { serve } from "@hono/node-server";
import { Hono } from "hono";
import { cors } from "hono/cors";
import { streamSSE } from "hono/streaming";
import { serveStatic } from "@hono/node-server/serve-static";
import { coderAgent } from "./agents/coder/agent.ts";
import { auditorAgent } from "./agents/auditor/agent.ts";
import { testerAgent } from "./agents/tester/agent.ts";
import { mapFindingToReport } from "./utils/mapFinding.js";
import { createEmptyFoundryProject } from "./utils/forgeSandbox.js";
import { logger, setLogSink, clearLogSink, setStepSink, clearStepSink } from "./logger.ts";
const app = new Hono();
app.use("/api/*", cors());
app.post("/api/run", (c) => {
return streamSSE(c, async (stream) => {
const body = await c.req.json<{ requirements: string }>();
const requirements = body.requirements?.trim();
if (!requirements) {
await stream.writeSSE({ event: "error", data: "Requisitos não fornecidos." });
return;
}
let eventId = 0;
const send = async (event: string, data: string) => {
await stream.writeSSE({ id: String(eventId++), event, data });
};
try {
setLogSink((msg) => send("log", msg));
setStepSink((event) => send("step", JSON.stringify(event)));
// === CODER ===
logger.info("[Coder] Gerando smart contract a partir dos requisitos...");
const coderResult = await coderAgent.invoke({ requirements: [requirements] });
if (coderResult.compilationErrors.length > 0) {
logger.info(`[Coder] Erros de compilação restantes: ${coderResult.compilationErrors.length}`);
} else {
logger.info("[Coder] Contrato compilado sem erros.");
}
await send(
"coder",
JSON.stringify({
contract: coderResult.contract,
compilationErrors: coderResult.compilationErrors,
reviewSummary: coderResult.reviewSummary,
}),
);
// === AUDITOR ===
const outputDir = resolve(tmpdir(), `talp1-${Date.now()}`);
mkdirSync(outputDir, { recursive: true });
writeFileSync(resolve(outputDir, "Contract.sol"), coderResult.contract, "utf-8");
writeFileSync(resolve(outputDir, "README.md"), requirements, "utf-8");
logger.info("[Auditor] Iniciando auditoria de segurança...");
const auditorResult = await auditorAgent.invoke({ repoPath: outputDir });
logger.info(`[Auditor] ${auditorResult.findings.length} vulnerabilidade(s) encontrada(s).`);
for (const f of auditorResult.findings) {
logger.info(`[Auditor] [${f.severity.toUpperCase()}] ${f.title} — ${f.location}`);
}
await send(
"auditor",
JSON.stringify({
findings: auditorResult.findings,
}),
);
// === TESTER ===
logger.info("[Tester] Gerando testes de prova de conceito...");
if (auditorResult.findings.length > 0) {
const report = mapFindingToReport(
auditorResult.findings[0],
coderResult.contract,
auditorResult.repoContext // ← now forwarded to tester
);
const sandboxDir = resolve(tmpdir(), `talp1-tester-${Date.now()}`);
await createEmptyFoundryProject(sandboxDir, coderResult.contract, "Contract");
report.customSandboxDir = sandboxDir; // ← tester runs in real project sandbox
report.affectedContract.sourceFilePath = "src/Contract.sol"; // Fix bug with relative path
const testerResult = await testerAgent.invoke(
{ report },
{ recursionLimit: 100, configurable: { sandboxDir } }
);
logger.info(`[Tester] Execução concluída com status: ${testerResult.status}`);
let finalPocCode = testerResult.pocCode || "";
try {
finalPocCode = readFileSync(resolve(sandboxDir, "test/Exploit.t.sol"), "utf-8");
} catch (e) {
// Ignorar se não criou
}
let finalExecutionLogs: string[] = testerResult.executionLogs || [];
if (finalExecutionLogs.length === 0 && testerResult.messages) {
const testMsgs = testerResult.messages.filter((m: any) => m._getType() === "tool" && m.name === "smart_contract_test");
if (testMsgs.length > 0) {
const content = testMsgs[testMsgs.length - 1].content;
finalExecutionLogs = [typeof content === "string" ? content : JSON.stringify(content)];
}
}
// Garante que o objeto enviado tem exatamente o que o front espera
await send(
"tester",
JSON.stringify({
status: testerResult.status,
pocCode: finalPocCode,
executionLogs: finalExecutionLogs,
iterations: testerResult.iterations,
}),
);
} else {
logger.info("[Tester] Nenhuma vulnerabilidade para testar.");
await send("tester", JSON.stringify({ status: "skipped", iterations: 0 }));
}
logger.info("Pipeline concluído.");
await send("done", "ok");
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
await send("error", message);
} finally {
clearLogSink();
clearStepSink();
}
});
});
// Serve static frontend files (built React app)
app.use("/*", serveStatic({ root: "./frontend/dist" }));
const port = Number(process.env.PORT) || 7860;
console.log(`Servidor rodando em http://localhost:${port}`);
serve({ fetch: app.fetch, port });
|