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.5",
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 result = await executeSlitherAnalyze(args, context);
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]*?)\]/