Spaces:
Runtime error
Runtime error
File size: 3,478 Bytes
184b6e6 5b62309 2c8beb8 | 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 | import fs from "node:fs";
import path from "node:path";
import { DOC_BASENAMES, DOC_EXTS, MAX_DEPTH, SKIP_DIRS, SOL_EXT, SOL_TEST_SUFFIXES } from "./config.ts";
export const walkDirectory = (dir: string, depth: number, solFiles: string[], docFiles: string[]) => {
if (depth > MAX_DEPTH) return;
let entries: fs.Dirent[];
try {
entries = fs.readdirSync(dir, { withFileTypes: true });
} catch {
return;
}
for (const entry of entries) {
if (entry.isDirectory()) {
if (!SKIP_DIRS.has(entry.name)) {
walkDirectory(path.join(dir, entry.name), depth + 1, solFiles, docFiles);
}
} else if (entry.isFile()) {
const fullPath = path.join(dir, entry.name);
const ext = path.extname(entry.name).toLowerCase();
const base = path.basename(entry.name, ext).toLowerCase();
if (ext === SOL_EXT) {
const isTest = SOL_TEST_SUFFIXES.some((suffix) => entry.name.endsWith(suffix));
if (!isTest) solFiles.push(fullPath);
} else if (DOC_EXTS.has(ext) || DOC_BASENAMES.has(base)) {
docFiles.push(fullPath);
}
}
}
};
export const matchLines = (fileContent: string, codeSnippet: string): string | null => {
const fileLines = fileContent.split("\n");
const snippetLines = codeSnippet.split("\n").map((line) => line.trim());
for (let i = 0; i < fileLines.length; i++) {
const fileLine = fileLines[i].trim();
if (fileLine === snippetLines[0]) {
let snippetIndex = 1;
const startLine = i + 1;
let endLine = i + 1;
let fileIndex = i + 1;
while (snippetIndex < snippetLines.length && fileIndex < fileLines.length) {
const currentFileLine = fileLines[fileIndex].trim();
if (currentFileLine === snippetLines[snippetIndex]) {
endLine = fileIndex + 1;
snippetIndex++;
}
fileIndex++;
}
if (snippetIndex === snippetLines.length) {
if (startLine === endLine) {
return `L${startLine}`;
}
return `L${startLine}-${endLine}`;
}
}
}
return null;
};
type ReviewEntry = {
finding: {
title: string;
severity: string;
location: string;
description: string;
codeSnippet: string;
};
review: {
isFalsePositive: boolean;
confidence: number;
review: string;
exploitablePaths: string[];
};
};
export const buildReviewBlocks = (fileEntries: ReviewEntry[], iterationCount: number): string => {
const blocks = fileEntries.map(({ finding, review }, i) => {
const verdict = review.isFalsePositive
? `FALSO POSITIVO (confiança: ${review.confidence}/100)`
: `VERDADEIRO POSITIVO (confiança: ${review.confidence}/100)`;
const pathsLabel = review.isFalsePositive ? "Razão de Bloqueio" : "Caminhos de Exploração";
const pathsContent =
review.exploitablePaths.length > 0
? review.exploitablePaths.map((p) => ` - ${p}`).join("\n")
: " (nenhum fornecido)";
return `[Achado ${i + 1}/${fileEntries.length}] ${finding.title}
Severidade: ${finding.severity}
Localização: linhas ${finding.location}
Descrição: ${finding.description}
Código:
\`\`\`solidity
${finding.codeSnippet}
\`\`\`
Veredito do Revisor: ${verdict}
Análise do Revisor: ${review.review}
${pathsLabel}:
${pathsContent}`;
});
return `=== Iteração ${iterationCount} — Achados e Revisões do Especialista (${fileEntries.length} achado(s)) ===\n\n${blocks.join("\n\n---\n\n")}`;
};
|