solidity-argus 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solidity-argus",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Solidity smart contract security auditing plugin for OpenCode — 4 specialized agents, 8 tools, and a curated vulnerability knowledge base",
|
|
5
5
|
"keywords": ["solidity", "security", "audit", "opencode", "plugin", "smart-contract", "ethereum", "defi", "slither", "foundry"],
|
|
6
6
|
"author": "Apegurus",
|
|
@@ -7,6 +7,8 @@ const RECOVERY_HINTS: Record<string, string> = {
|
|
|
7
7
|
scvd: "Check SCVD API at https://api.scvd.dev — may be temporarily unavailable",
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
const VIA_IR_HINT = "Project uses via_ir — Slither uses forge-flatten fallback automatically. Ensure forge and solc-select are installed."
|
|
11
|
+
|
|
10
12
|
export function createToolErrorRecoveryHandler() {
|
|
11
13
|
const logger = createLogger()
|
|
12
14
|
|
|
@@ -14,6 +16,17 @@ export function createToolErrorRecoveryHandler() {
|
|
|
14
16
|
const { tool, result } = toolResult
|
|
15
17
|
const lowerResult = result.toLowerCase()
|
|
16
18
|
|
|
19
|
+
const isViaIr =
|
|
20
|
+
lowerResult.includes("via_ir") ||
|
|
21
|
+
lowerResult.includes("via-ir") ||
|
|
22
|
+
lowerResult.includes("flatten fallback") ||
|
|
23
|
+
lowerResult.includes("flatten-fallback")
|
|
24
|
+
|
|
25
|
+
if (isViaIr && tool.includes("slither")) {
|
|
26
|
+
logger.info(`Tool error recovery hint for ${tool}: ${VIA_IR_HINT}`)
|
|
27
|
+
return `\n[Argus Recovery Hint] ${VIA_IR_HINT}`
|
|
28
|
+
}
|
|
29
|
+
|
|
17
30
|
const isError =
|
|
18
31
|
lowerResult.includes("enoent") ||
|
|
19
32
|
lowerResult.includes("not found") ||
|
|
@@ -12,6 +12,7 @@ type SlitherArgs = {
|
|
|
12
12
|
detectors?: string[];
|
|
13
13
|
exclude?: string[];
|
|
14
14
|
solc_version?: string;
|
|
15
|
+
via_ir?: boolean;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
type SlitherDetector = {
|
|
@@ -135,6 +136,12 @@ const FALLBACK_TRIGGERS = [
|
|
|
135
136
|
"crytic_compile",
|
|
136
137
|
"empty AST",
|
|
137
138
|
"Compilation failed",
|
|
139
|
+
"via_ir",
|
|
140
|
+
"via-ir",
|
|
141
|
+
"viaIR",
|
|
142
|
+
"YulException",
|
|
143
|
+
"StackTooDeep",
|
|
144
|
+
"Stack too deep",
|
|
138
145
|
];
|
|
139
146
|
|
|
140
147
|
function shouldTryFlattenFallback(errors: string[], stderr: string): boolean {
|
|
@@ -354,9 +361,26 @@ export async function executeSlitherAnalyze(
|
|
|
354
361
|
runCommand: RunSlitherCommand = runSlitherCommand
|
|
355
362
|
): Promise<SlitherAnalyzeResult> {
|
|
356
363
|
const startedAt = Date.now();
|
|
357
|
-
const command = buildCommand(args);
|
|
358
364
|
context.metadata({ title: `Slither analysis: ${args.target}` });
|
|
359
365
|
|
|
366
|
+
if (args.via_ir) {
|
|
367
|
+
const fallbackResult = await flattenFallback(args, context, {
|
|
368
|
+
...defaultFlattenDeps,
|
|
369
|
+
runCommand,
|
|
370
|
+
});
|
|
371
|
+
if (fallbackResult) return fallbackResult;
|
|
372
|
+
return {
|
|
373
|
+
success: false,
|
|
374
|
+
findingsCount: 0,
|
|
375
|
+
findings: [],
|
|
376
|
+
executionTime: Date.now() - startedAt,
|
|
377
|
+
errors: ["via_ir enabled — flatten fallback failed. Ensure forge and solc are available."],
|
|
378
|
+
error: "Project uses via_ir which is incompatible with Slither direct analysis. Flatten fallback also failed.",
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const command = buildCommand(args);
|
|
383
|
+
|
|
360
384
|
try {
|
|
361
385
|
const runResult = await runCommand(command, context.abort);
|
|
362
386
|
const errors: string[] = [];
|
|
@@ -449,6 +473,18 @@ export async function executeSlitherAnalyze(
|
|
|
449
473
|
}
|
|
450
474
|
}
|
|
451
475
|
|
|
476
|
+
export function detectViaIr(target: string): boolean {
|
|
477
|
+
const projectDir = target.endsWith(".sol") ? join(target, "..") : target;
|
|
478
|
+
const foundryTomlPath = join(projectDir, "foundry.toml");
|
|
479
|
+
if (!existsSync(foundryTomlPath)) return false;
|
|
480
|
+
try {
|
|
481
|
+
const content = readFileSync(foundryTomlPath, "utf-8");
|
|
482
|
+
return /^\s*via[_-]ir\s*=\s*true/m.test(content);
|
|
483
|
+
} catch {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
452
488
|
export const slitherTool = tool({
|
|
453
489
|
description:
|
|
454
490
|
"Run Slither static analysis and return normalized findings for Solidity targets.",
|
|
@@ -459,7 +495,8 @@ export const slitherTool = tool({
|
|
|
459
495
|
solc_version: tool.schema.string().optional(),
|
|
460
496
|
},
|
|
461
497
|
async execute(args, context) {
|
|
462
|
-
const
|
|
498
|
+
const viaIr = detectViaIr(args.target);
|
|
499
|
+
const result = await executeSlitherAnalyze({ ...args, via_ir: viaIr }, context);
|
|
463
500
|
return JSON.stringify(result);
|
|
464
501
|
},
|
|
465
502
|
});
|
|
@@ -7,6 +7,7 @@ export interface ProjectConfig {
|
|
|
7
7
|
testDir: string;
|
|
8
8
|
solcVersion?: string;
|
|
9
9
|
remappings: string[];
|
|
10
|
+
viaIr: boolean;
|
|
10
11
|
rootDir: string;
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -43,6 +44,7 @@ export async function detectProject(dir: string): Promise<ProjectConfig> {
|
|
|
43
44
|
let testDir = "test";
|
|
44
45
|
let solcVersion: string | undefined;
|
|
45
46
|
let remappings: string[] = [];
|
|
47
|
+
let viaIr = false;
|
|
46
48
|
|
|
47
49
|
// Parse Foundry config if present
|
|
48
50
|
if (hasFoundry) {
|
|
@@ -51,6 +53,7 @@ export async function detectProject(dir: string): Promise<ProjectConfig> {
|
|
|
51
53
|
testDir = foundryConfig.testDir || testDir;
|
|
52
54
|
solcVersion = foundryConfig.solcVersion;
|
|
53
55
|
remappings = foundryConfig.remappings;
|
|
56
|
+
viaIr = foundryConfig.viaIr;
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
// Set Hardhat defaults if it's a Hardhat project
|
|
@@ -64,6 +67,7 @@ export async function detectProject(dir: string): Promise<ProjectConfig> {
|
|
|
64
67
|
testDir,
|
|
65
68
|
solcVersion,
|
|
66
69
|
remappings,
|
|
70
|
+
viaIr,
|
|
67
71
|
rootDir,
|
|
68
72
|
};
|
|
69
73
|
}
|
|
@@ -78,6 +82,7 @@ async function parseFoundryToml(
|
|
|
78
82
|
testDir?: string;
|
|
79
83
|
solcVersion?: string;
|
|
80
84
|
remappings: string[];
|
|
85
|
+
viaIr: boolean;
|
|
81
86
|
}> {
|
|
82
87
|
const content = await Bun.file(filePath).text();
|
|
83
88
|
|
|
@@ -86,6 +91,7 @@ async function parseFoundryToml(
|
|
|
86
91
|
testDir: undefined as string | undefined,
|
|
87
92
|
solcVersion: undefined as string | undefined,
|
|
88
93
|
remappings: [] as string[],
|
|
94
|
+
viaIr: false,
|
|
89
95
|
};
|
|
90
96
|
|
|
91
97
|
// Extract [profile.default] section - stop at next section or EOF
|
|
@@ -116,6 +122,12 @@ async function parseFoundryToml(
|
|
|
116
122
|
result.solcVersion = solcMatch[1];
|
|
117
123
|
}
|
|
118
124
|
|
|
125
|
+
// Parse via_ir = true/false
|
|
126
|
+
const viaIrMatch = profileSection.match(/^\s*via[_-]ir\s*=\s*(true|false)/m);
|
|
127
|
+
if (viaIrMatch && viaIrMatch[1] === "true") {
|
|
128
|
+
result.viaIr = true;
|
|
129
|
+
}
|
|
130
|
+
|
|
119
131
|
// Parse remappings array - handles both single line and multiline
|
|
120
132
|
const remappingsMatch = profileSection.match(
|
|
121
133
|
/remappings\s*=\s*\[([\s\S]*?)\]/
|