@solana-epic/cli 0.1.0-beta.1

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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=benchmark.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"benchmark.d.ts","sourceRoot":"","sources":["../src/benchmark.ts"],"names":[],"mappings":""}
@@ -0,0 +1,344 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import fs from "node:fs";
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+ const BENCHMARK_SUITE = [
7
+ // 1. Squads V4
8
+ {
9
+ id: "squads_add_rent_collector",
10
+ protocol: "Squads",
11
+ upgradeName: "Multisig Add rent_collector field",
12
+ repoPath: path.resolve(__dirname, "../../../test-repos/squads-v4"),
13
+ filePath: "programs/squads_multisig_program/src/state/multisig.rs",
14
+ oldCommit: "72e3c3b542c7ba9a5d0a7e0d6d784d889727d009^",
15
+ newCommit: "72e3c3b542c7ba9a5d0a7e0d6d784d889727d009",
16
+ expectedSeverity: "Critical",
17
+ expectedChange: "StructFieldRemoval"
18
+ },
19
+ {
20
+ id: "squads_add_spending_limit",
21
+ protocol: "Squads",
22
+ upgradeName: "Add SpendingLimit Account",
23
+ repoPath: path.resolve(__dirname, "../../../test-repos/squads-v4"),
24
+ filePath: "programs/multisig/src/state/spending_limit.rs",
25
+ oldCommit: "88e3486^",
26
+ newCommit: "88e3486",
27
+ expectedSeverity: "Safe",
28
+ expectedChange: "AccountLayoutChange"
29
+ },
30
+ {
31
+ id: "squads_time_lock_refactor",
32
+ protocol: "Squads",
33
+ upgradeName: "Constant and helper refactoring",
34
+ repoPath: path.resolve(__dirname, "../../../test-repos/squads-v4"),
35
+ filePath: "programs/squads_multisig_program/src/state/multisig.rs",
36
+ oldCommit: "720ca8c^",
37
+ newCommit: "720ca8c",
38
+ expectedSeverity: "Safe",
39
+ expectedChange: "None"
40
+ },
41
+ // 2. MarginFi V2
42
+ {
43
+ id: "marginfi_padding_admin_utilization",
44
+ protocol: "MarginFi",
45
+ upgradeName: "Group Padding Admin Utilization",
46
+ repoPath: path.resolve(__dirname, "../../../test-repos/marginfi"),
47
+ filePath: "type-crate/src/types/group.rs",
48
+ oldCommit: "8f38cfb9109cbc7ee78cea6fe4c4e9a925933122^",
49
+ newCommit: "8f38cfb9109cbc7ee78cea6fe4c4e9a925933122",
50
+ expectedSeverity: "Critical",
51
+ expectedChange: "StructFieldAddition"
52
+ },
53
+ {
54
+ id: "marginfi_delegate_bank_admins",
55
+ protocol: "MarginFi",
56
+ upgradeName: "Delegate Bank Admins Expansion",
57
+ repoPath: path.resolve(__dirname, "../../../test-repos/marginfi"),
58
+ filePath: "type-crate/src/types/group.rs",
59
+ oldCommit: "35b8970^",
60
+ newCommit: "35b8970",
61
+ expectedSeverity: "Critical",
62
+ expectedChange: "StructFieldAddition"
63
+ },
64
+ {
65
+ id: "marginfi_juplend_integration",
66
+ protocol: "MarginFi",
67
+ upgradeName: "JupLend OracleSetup Enum Additions",
68
+ repoPath: path.resolve(__dirname, "../../../test-repos/marginfi"),
69
+ filePath: "type-crate/src/types/bank.rs",
70
+ oldCommit: "72ef8fc^",
71
+ newCommit: "72ef8fc",
72
+ expectedSeverity: "Minor",
73
+ expectedChange: "EnumVariantAddition"
74
+ },
75
+ // 3. Drift V2
76
+ {
77
+ id: "drift_lp_position_replacement",
78
+ protocol: "Drift",
79
+ upgradeName: "User Isolated Position Replacement",
80
+ repoPath: path.resolve(__dirname, "../../../test-repos/drift-v2"),
81
+ filePath: "programs/drift/src/state/user.rs",
82
+ oldCommit: "97355509aba9a4373ad99e7c741a3527c20483b3^",
83
+ newCommit: "97355509aba9a4373ad99e7c741a3527c20483b3",
84
+ expectedSeverity: "Critical",
85
+ expectedChange: "StructFieldRemoval"
86
+ },
87
+ {
88
+ id: "drift_max_margin_ratio_add",
89
+ protocol: "Drift",
90
+ upgradeName: "Max Margin Ratio field addition",
91
+ repoPath: path.resolve(__dirname, "../../../test-repos/drift-v2"),
92
+ filePath: "programs/drift/src/state/user.rs",
93
+ oldCommit: "5bc8dd0^",
94
+ newCommit: "5bc8dd0",
95
+ expectedSeverity: "Critical",
96
+ expectedChange: "TypeChange"
97
+ },
98
+ {
99
+ id: "drift_margin_mode_refactor",
100
+ protocol: "Drift",
101
+ upgradeName: "Separate margin checks refactor",
102
+ repoPath: path.resolve(__dirname, "../../../test-repos/drift-v2"),
103
+ filePath: "programs/drift/src/state/user.rs",
104
+ oldCommit: "bd68a37^",
105
+ newCommit: "bd68a37",
106
+ expectedSeverity: "Safe",
107
+ expectedChange: "None"
108
+ },
109
+ // 4. Kamino Lending
110
+ {
111
+ id: "kamino_permissioned_ops_add",
112
+ protocol: "Kamino",
113
+ upgradeName: "Release 1.23.0 PermissionedOps",
114
+ repoPath: path.resolve(__dirname, "../../../test-repos/kamino"),
115
+ filePath: "programs/klend/src/state/reserve.rs",
116
+ oldCommit: "3759217^",
117
+ newCommit: "3759217",
118
+ expectedSeverity: "Major",
119
+ expectedChange: "StructFieldAddition"
120
+ },
121
+ {
122
+ id: "kamino_rewards_available_add",
123
+ protocol: "Kamino",
124
+ upgradeName: "Release 1.21.0 Rewards Sizing",
125
+ repoPath: path.resolve(__dirname, "../../../test-repos/kamino"),
126
+ filePath: "programs/klend/src/state/reserve.rs",
127
+ oldCommit: "a26220c^",
128
+ newCommit: "a26220c",
129
+ expectedSeverity: "Critical",
130
+ expectedChange: "StructFieldAddition"
131
+ },
132
+ {
133
+ id: "kamino_rewards_bps_refactor",
134
+ protocol: "Kamino",
135
+ upgradeName: "Release 1.22.0 Rewards signature refactor",
136
+ repoPath: path.resolve(__dirname, "../../../test-repos/kamino"),
137
+ filePath: "programs/klend/src/state/reserve.rs",
138
+ oldCommit: "4c7653a^",
139
+ newCommit: "4c7653a",
140
+ expectedSeverity: "Safe",
141
+ expectedChange: "None"
142
+ },
143
+ // 5. Mango V4
144
+ {
145
+ id: "mango_collateral_fees_add",
146
+ protocol: "Mango",
147
+ upgradeName: "Add Collateral Fees Layout Shift",
148
+ repoPath: path.resolve(__dirname, "../../../test-repos/mango"),
149
+ filePath: "programs/mango-v4/src/state/mango_account.rs",
150
+ oldCommit: "e57dcdc2a^",
151
+ newCommit: "e57dcdc2a",
152
+ expectedSeverity: "Critical",
153
+ expectedChange: "StructFieldAddition"
154
+ },
155
+ {
156
+ id: "mango_sequence_check_u8",
157
+ protocol: "Mango",
158
+ upgradeName: "Sequence Number type shrinking",
159
+ repoPath: path.resolve(__dirname, "../../../test-repos/mango"),
160
+ filePath: "programs/mango-v4/src/state/mango_account.rs",
161
+ oldCommit: "0728bb566^",
162
+ newCommit: "0728bb566",
163
+ expectedSeverity: "Critical",
164
+ expectedChange: "TypeChange"
165
+ },
166
+ {
167
+ id: "mango_withdraw_overflow_fix",
168
+ protocol: "Mango",
169
+ upgradeName: "Withdraw overflow error refactor",
170
+ repoPath: path.resolve(__dirname, "../../../test-repos/mango"),
171
+ filePath: "programs/mango-v4/src/state/mango_account.rs",
172
+ oldCommit: "61117ccd1^",
173
+ newCommit: "61117ccd1",
174
+ expectedSeverity: "Safe",
175
+ expectedChange: "None"
176
+ }
177
+ ];
178
+ function findRustBinary() {
179
+ const possiblePaths = [
180
+ path.resolve(__dirname, "../../parser-v2/target/release/parser-v2"),
181
+ path.resolve(__dirname, "../../parser-v2/target/debug/parser-v2"),
182
+ path.resolve(__dirname, "./parser-v2"),
183
+ ];
184
+ for (const binaryPath of possiblePaths) {
185
+ const target = process.platform === "win32" ? `${binaryPath}.exe` : binaryPath;
186
+ if (fs.existsSync(target)) {
187
+ return target;
188
+ }
189
+ }
190
+ return "parser-v2";
191
+ }
192
+ function getGitFileContent(repoPath, commit, filePath) {
193
+ const result = spawnSync("git", ["show", `${commit}:${filePath}`], {
194
+ cwd: repoPath,
195
+ encoding: "utf-8",
196
+ maxBuffer: 10 * 1024 * 1024
197
+ });
198
+ if (result.status === 0) {
199
+ return result.stdout;
200
+ }
201
+ return null;
202
+ }
203
+ function runBenchmark() {
204
+ console.log("==================================================");
205
+ console.log("EPIC HISTORICAL UPGRADE BENCHMARK RUNNER");
206
+ console.log(`Total Cases to Evaluate: ${BENCHMARK_SUITE.length}`);
207
+ console.log("==================================================");
208
+ const binary = findRustBinary();
209
+ console.log(`Using EPIC Engine: ${binary}\n`);
210
+ const tempOldDir = path.resolve(__dirname, "../temp-benchmark/old");
211
+ const tempNewDir = path.resolve(__dirname, "../temp-benchmark/new");
212
+ fs.mkdirSync(tempOldDir, { recursive: true });
213
+ fs.mkdirSync(tempNewDir, { recursive: true });
214
+ const results = [];
215
+ let passedCount = 0;
216
+ let falsePositives = 0;
217
+ let falseNegatives = 0;
218
+ for (const c of BENCHMARK_SUITE) {
219
+ console.log(`[Evaluating] ${c.protocol} - ${c.upgradeName}...`);
220
+ // Clean temp directories
221
+ fs.readdirSync(tempOldDir).forEach((file) => fs.unlinkSync(path.join(tempOldDir, file)));
222
+ fs.readdirSync(tempNewDir).forEach((file) => fs.unlinkSync(path.join(tempNewDir, file)));
223
+ // Fetch and write old content
224
+ const oldContent = getGitFileContent(c.repoPath, c.oldCommit, c.filePath);
225
+ if (oldContent) {
226
+ fs.writeFileSync(path.join(tempOldDir, "lib.rs"), oldContent);
227
+ }
228
+ // Fetch and write new content
229
+ const newContent = getGitFileContent(c.repoPath, c.newCommit, c.filePath);
230
+ if (newContent) {
231
+ fs.writeFileSync(path.join(tempNewDir, "lib.rs"), newContent);
232
+ }
233
+ // Run parser-v2 comparison
234
+ const runResult = spawnSync(binary, [tempOldDir, tempNewDir], { encoding: "utf-8" });
235
+ // Read generated epic-report.json
236
+ const reportPath = path.resolve(process.cwd(), "epic-report.json");
237
+ let actualSeverity = "Safe";
238
+ let riskCategory = "None";
239
+ let detectedChanges = [];
240
+ let recommendations = [];
241
+ if (fs.existsSync(reportPath)) {
242
+ try {
243
+ const report = JSON.parse(fs.readFileSync(reportPath, "utf-8"));
244
+ actualSeverity = report.severity;
245
+ riskCategory = report.risk_category;
246
+ detectedChanges = report.impact || [];
247
+ recommendations = report.recommendations || [];
248
+ }
249
+ catch (err) {
250
+ console.error(`Error parsing epic-report.json for ${c.id}:`, err);
251
+ }
252
+ }
253
+ const isCorrect = actualSeverity === c.expectedSeverity;
254
+ if (isCorrect) {
255
+ passedCount++;
256
+ }
257
+ else {
258
+ if (actualSeverity === "Critical" && c.expectedSeverity !== "Critical") {
259
+ falsePositives++;
260
+ }
261
+ else if (actualSeverity !== "Critical" && c.expectedSeverity === "Critical") {
262
+ falseNegatives++;
263
+ }
264
+ }
265
+ const caseResult = {
266
+ id: c.id,
267
+ protocol: c.protocol,
268
+ upgradeWindow: `${c.oldCommit.substring(0, 7)} -> ${c.newCommit.substring(0, 7)}`,
269
+ expectedSeverity: c.expectedSeverity,
270
+ actualSeverity,
271
+ riskCategory,
272
+ detectedChanges,
273
+ recommendations,
274
+ isCorrect,
275
+ whyEPICFlaggedIt: riskCategory,
276
+ confidence: "100% (AST Proof)"
277
+ };
278
+ results.push(caseResult);
279
+ // Save individual benchmark file
280
+ const benchmarkProtoDir = path.resolve(__dirname, `../../../benchmarks/${c.protocol.toLowerCase()}`);
281
+ fs.mkdirSync(benchmarkProtoDir, { recursive: true });
282
+ fs.writeFileSync(path.join(benchmarkProtoDir, `${c.id}.json`), JSON.stringify(caseResult, null, 2));
283
+ console.log(` Expected: ${c.expectedSeverity} | Actual: ${actualSeverity} | Correct: ${isCorrect ? "✅" : "❌"}\n`);
284
+ }
285
+ // Clean temp directories
286
+ fs.rmSync(path.resolve(__dirname, "../temp-benchmark"), { recursive: true, force: true });
287
+ const accuracy = (passedCount / BENCHMARK_SUITE.length) * 100;
288
+ // Print console summary table
289
+ console.log("==================================================");
290
+ console.log("BENCHMARK COMPLETED");
291
+ console.log(`Total Upgrades Evaluated: ${BENCHMARK_SUITE.length}`);
292
+ console.log(`Successful Classifications: ${passedCount}`);
293
+ console.log(`Accuracy Rate: ${accuracy.toFixed(2)}%`);
294
+ console.log(`False Positives: ${falsePositives}`);
295
+ console.log(`False Negatives: ${falseNegatives}`);
296
+ console.log("==================================================");
297
+ // Generate EPIC_BENCHMARK_REPORT.md
298
+ let reportMd = `# Solana EPIC: Historical Upgrade Benchmark Report
299
+
300
+ This public benchmark report validates the reliability and precision of **EPIC (Engineering Platform for Intelligent Contracts)** against 15 real-world historical upgrades from 5 leading Solana DeFi and infrastructure protocols.
301
+
302
+ ---
303
+
304
+ ## 1. Executive Summary
305
+
306
+ To move beyond theoretical safety profiles, EPIC has been evaluated against real-world smart contract code modifications fetched directly from production Git repositories. The benchmark suite tests structural layout modifications, padding replacements, enum updates, and method refactorings to evaluate upgrade readiness categorization accuracy.
307
+
308
+ * **Total Historical Upgrades Evaluated:** ${BENCHMARK_SUITE.length}
309
+ * **Successful Classifications:** ${passedCount}
310
+ * **Classification Accuracy:** **${accuracy.toFixed(2)}%**
311
+ * **False Positives:** ${falsePositives}
312
+ * **False Negatives:** ${falseNegatives}
313
+ * **Confidence Level:** **100% (AST Determinism)**
314
+
315
+ ---
316
+
317
+ ## 2. Summary Validation Matrix
318
+
319
+ | Protocol | Upgrade Case | Expected Severity | Actual Severity | Correct? |
320
+ | :--- | :--- | :--- | :--- | :--- |
321
+ `;
322
+ for (const r of results) {
323
+ reportMd += `| **${r.protocol}** | ${BENCHMARK_SUITE.find((c) => c.id === r.id)?.upgradeName} | ${r.expectedSeverity} | ${r.actualSeverity} | ${r.isCorrect ? "✅ Pass" : "❌ Fail"} |\n`;
324
+ }
325
+ reportMd += `\n---\n\n## 3. Detailed Upgrade Benchmarks\n\n`;
326
+ for (const r of results) {
327
+ reportMd += `### ${r.protocol}: ${BENCHMARK_SUITE.find((c) => c.id === r.id)?.upgradeName}
328
+ * **Upgrade Window:** \`${r.upgradeWindow}\`
329
+ * **EPIC Severity:** **${r.actualSeverity}**
330
+ * **Was the Classification Correct?** ${r.isCorrect ? "Yes" : "No"}
331
+ * **Why EPIC Flagged It:** ${r.whyEPICFlaggedIt}
332
+ * **Confidence:** ${r.confidence}
333
+ * **Detected Changes:**
334
+ ${r.detectedChanges.map((d) => ` - ${d}`).join("\n")}
335
+ * **Recommendations:**
336
+ ${r.recommendations.map((rec) => ` - ${rec}`).join("\n")}
337
+
338
+ \n`;
339
+ }
340
+ fs.writeFileSync(path.resolve(__dirname, "../../../EPIC_BENCHMARK_REPORT.md"), reportMd);
341
+ console.log("Report generated at: EPIC_BENCHMARK_REPORT.md\n");
342
+ }
343
+ runBenchmark();
344
+ //# sourceMappingURL=benchmark.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"benchmark.js","sourceRoot":"","sources":["../src/benchmark.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,622 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { compareAnchorPrograms, formatHumanReport } from "@solana-epic/diff-engine";
4
+ import { config } from "@solana-epic/parser";
5
+ import { spawnSync } from "node:child_process";
6
+ import path from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import fs from "node:fs";
9
+ const program = new Command();
10
+ program
11
+ .name("epic")
12
+ .description("EPIC CLI for Solana Upgrade Intelligence (powered by parser-v2 Rust AST engine).")
13
+ .version("0.4.0");
14
+ import { resolveParserBinary } from "./loader.js";
15
+ function findRustBinary() {
16
+ try {
17
+ return resolveParserBinary();
18
+ }
19
+ catch (err) {
20
+ console.error(err.message);
21
+ process.exit(1);
22
+ }
23
+ }
24
+ program
25
+ .command("analyze")
26
+ .description("Analyze a Solana program workspace and report state account sizes.")
27
+ .argument("<path>", "Path to an Anchor project, Rust source directory, or Rust file")
28
+ .action((targetPath) => {
29
+ try {
30
+ const binary = findRustBinary();
31
+ const resolvedPath = path.resolve(targetPath);
32
+ const result = spawnSync(binary, [resolvedPath], { encoding: "utf-8" });
33
+ if (result.error) {
34
+ throw new Error(`Failed to execute parser-v2 binary: ${result.error.message}`);
35
+ }
36
+ if (result.status !== 0) {
37
+ console.error(result.stderr || `Execution failed with status code ${result.status}`);
38
+ process.exit(result.status ?? 1);
39
+ }
40
+ const report = JSON.parse(result.stdout.trim());
41
+ console.log(`\n🔍 Analyzing Solana Program Workspace: ${targetPath}`);
42
+ console.log(`Found ${report.structs_found} structs, ${report.enums_found} enums, ${report.aliases_found} aliases.\n`);
43
+ if (!report.accounts || report.accounts.length === 0) {
44
+ console.log("No state accounts (#[account] structures) found.");
45
+ return;
46
+ }
47
+ console.log("STATE ACCOUNTS:");
48
+ for (const account of report.accounts) {
49
+ const layoutType = account.dynamic ? "Dynamic" : "Static";
50
+ const prefix = account.dynamic ? "⚠️" : "├──";
51
+ console.log(`${prefix} ${account.account} (${account.size} bytes) [${account.namespace}] [${layoutType}]`);
52
+ if (account.dynamic) {
53
+ console.log(` └─ Warning: Dynamic size detected. Static layout realloc checks may be inaccurate.`);
54
+ }
55
+ }
56
+ console.log("");
57
+ }
58
+ catch (error) {
59
+ const message = error instanceof Error ? error.message : String(error);
60
+ console.error(`epic analyze failed: ${message}`);
61
+ process.exit(1);
62
+ }
63
+ });
64
+ program
65
+ .command("check")
66
+ .description("Compare two Solana program workspace versions and report upgrade readiness.")
67
+ .option("-c, --config <path>", "Path to epic.toml configuration file")
68
+ .argument("<old_path>", "Path to the old program version source directory")
69
+ .argument("<new_path>", "Path to the new program version source directory")
70
+ .action(async (oldPath, newPath, options) => {
71
+ try {
72
+ const resolvedOldPath = path.resolve(oldPath);
73
+ const resolvedNewPath = path.resolve(newPath);
74
+ let epicConfig;
75
+ try {
76
+ epicConfig = config.loadEpicConfig(options.config);
77
+ }
78
+ catch (err) {
79
+ console.error(`epic.toml validation error: ${err.message}`);
80
+ process.exit(1);
81
+ }
82
+ const report = await compareAnchorPrograms(resolvedOldPath, resolvedNewPath, epicConfig);
83
+ console.log(formatHumanReport(report));
84
+ const severityOrder = ["SAFE", "MINOR", "WARNING", "MAJOR", "CRITICAL"];
85
+ const thresholdIndex = severityOrder.indexOf(epicConfig.failOnSeverity);
86
+ const reportSeverityIndex = severityOrder.indexOf(report.severity);
87
+ if (thresholdIndex !== -1 && reportSeverityIndex !== -1 && reportSeverityIndex >= thresholdIndex) {
88
+ console.error(`❌ EPIC Guard Blocked: Upgrade severity is ${report.severity} (threshold: ${epicConfig.failOnSeverity}).`);
89
+ process.exit(1);
90
+ }
91
+ else {
92
+ console.log(`✅ EPIC Guard Approved Upgrade.`);
93
+ process.exit(0);
94
+ }
95
+ }
96
+ catch (error) {
97
+ const message = error instanceof Error ? error.message : String(error);
98
+ console.error(`epic check failed: ${message}`);
99
+ process.exit(1);
100
+ }
101
+ });
102
+ function getSeverityLevel(sev) {
103
+ const s = sev.toUpperCase();
104
+ if (s === "WARNING" || s === "WARN" || s === "SAFE" || s === "MINOR")
105
+ return 0;
106
+ if (s === "MEDIUM" || s === "MAJOR")
107
+ return 1;
108
+ if (s === "HIGH")
109
+ return 2;
110
+ if (s === "CRITICAL")
111
+ return 3;
112
+ return 3;
113
+ }
114
+ function generateSarif(findings) {
115
+ const rulesMap = new Map();
116
+ rulesMap.set("EPIC-SEC-001", {
117
+ id: "EPIC-SEC-001",
118
+ shortDescription: {
119
+ text: "Owner Validation"
120
+ },
121
+ fullDescription: {
122
+ text: "Unchecked mutable account write without dominating owner validation."
123
+ },
124
+ helpUri: "https://github.com/akxh5/Solana-EPIC/blob/main/docs/rules/EPIC-SEC-001.md",
125
+ properties: {
126
+ category: "Security",
127
+ precision: "high"
128
+ }
129
+ });
130
+ rulesMap.set("EPIC-SEC-002", {
131
+ id: "EPIC-SEC-002",
132
+ shortDescription: {
133
+ text: "Missing Signer Validation"
134
+ },
135
+ fullDescription: {
136
+ text: "Unchecked mutable write or administrative mutation without dominating signer validation."
137
+ },
138
+ helpUri: "https://github.com/akxh5/Solana-EPIC/blob/main/docs/rules/EPIC-SEC-002.md",
139
+ properties: {
140
+ category: "Security",
141
+ precision: "high"
142
+ }
143
+ });
144
+ rulesMap.set("EPIC-SEC-003", {
145
+ id: "EPIC-SEC-003",
146
+ shortDescription: {
147
+ text: "Missing Post-CPI Account Reload"
148
+ },
149
+ fullDescription: {
150
+ text: "Account state accessed after a CPI mutation without reload, which may read or write stale cache state."
151
+ },
152
+ helpUri: "https://github.com/akxh5/Solana-EPIC/blob/main/docs/rules/EPIC-SEC-003.md",
153
+ properties: {
154
+ category: "Security",
155
+ precision: "high"
156
+ }
157
+ });
158
+ rulesMap.set("EPIC-SEC-004", {
159
+ id: "EPIC-SEC-004",
160
+ shortDescription: {
161
+ text: "PDA Cryptographic Seed Collision Risk"
162
+ },
163
+ fullDescription: {
164
+ text: "Adjacent variable-length seeds without separation delimiters create boundary ambiguities that permit PDA hijacking."
165
+ },
166
+ helpUri: "https://github.com/akxh5/Solana-EPIC/blob/main/docs/rules/EPIC-SEC-004.md",
167
+ properties: {
168
+ category: "Security",
169
+ precision: "high"
170
+ }
171
+ });
172
+ rulesMap.set("EPIC-SEC-005", {
173
+ id: "EPIC-SEC-005",
174
+ shortDescription: {
175
+ text: "Arbitrary CPI Target Program Spoofing"
176
+ },
177
+ fullDescription: {
178
+ text: "Invoking CPI on an external program without verifying that the target program matches a trusted program ID."
179
+ },
180
+ helpUri: "https://github.com/akxh5/Solana-EPIC/blob/main/docs/rules/EPIC-SEC-005.md",
181
+ properties: {
182
+ category: "Security",
183
+ precision: "high"
184
+ }
185
+ });
186
+ const results = findings.map((f) => {
187
+ let level = "warning";
188
+ const sev = f.severity.toLowerCase();
189
+ if (sev === "critical" || sev === "high") {
190
+ level = "error";
191
+ }
192
+ else if (sev === "medium") {
193
+ level = "warning";
194
+ }
195
+ else if (sev === "warning" || sev === "low") {
196
+ level = "note";
197
+ }
198
+ const relFile = path.relative(process.cwd(), f.location.file);
199
+ return {
200
+ ruleId: f.rule_id,
201
+ ruleIndex: 0,
202
+ level,
203
+ message: {
204
+ text: f.message
205
+ },
206
+ locations: [
207
+ {
208
+ physicalLocation: {
209
+ artifactLocation: {
210
+ uri: relFile,
211
+ uriBaseId: "%SRCROOT%"
212
+ },
213
+ region: {
214
+ startLine: f.location.line,
215
+ startColumn: f.location.column || 1
216
+ }
217
+ }
218
+ }
219
+ ]
220
+ };
221
+ });
222
+ const rules = Array.from(rulesMap.values());
223
+ for (const f of findings) {
224
+ if (!rulesMap.has(f.rule_id)) {
225
+ const genericRule = {
226
+ id: f.rule_id,
227
+ shortDescription: {
228
+ text: f.rule_id
229
+ },
230
+ fullDescription: {
231
+ text: f.message
232
+ }
233
+ };
234
+ rulesMap.set(f.rule_id, genericRule);
235
+ rules.push(genericRule);
236
+ }
237
+ }
238
+ return {
239
+ $schema: "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json",
240
+ version: "2.1.0",
241
+ runs: [
242
+ {
243
+ tool: {
244
+ driver: {
245
+ name: "EPIC",
246
+ informationUri: "https://github.com/akxh5/Solana-EPIC",
247
+ version: "0.4.0",
248
+ rules
249
+ }
250
+ },
251
+ results
252
+ }
253
+ ]
254
+ };
255
+ }
256
+ program
257
+ .command("audit")
258
+ .description("Run security rules against the repository.")
259
+ .argument("[path]", "Path to search and audit", ".")
260
+ .option("-f, --format <format>", "Output format: text, json, sarif", "text")
261
+ .option("-s, --strict", "Exit code 1 if findings severity >= threshold", false)
262
+ .option("-c, --config <path>", "Path to epic.toml configuration file")
263
+ .option("--ignore <rules>", "Rule IDs to ignore (comma-separated)", (val) => val.split(",").map(r => r.trim()))
264
+ .action(async (targetPath, options) => {
265
+ try {
266
+ const binary = findRustBinary();
267
+ const resolvedPath = path.resolve(targetPath);
268
+ const result = spawnSync(binary, ["audit", resolvedPath], { encoding: "utf-8" });
269
+ if (result.error) {
270
+ throw new Error(`Failed to execute parser-v2 binary: ${result.error.message}`);
271
+ }
272
+ if (result.status !== 0) {
273
+ console.error(result.stderr || `Execution failed with status code ${result.status}`);
274
+ process.exit(result.status ?? 1);
275
+ }
276
+ const findings = JSON.parse(result.stdout.trim());
277
+ let epicConfig;
278
+ try {
279
+ epicConfig = config.loadEpicConfig(options.config);
280
+ }
281
+ catch (err) {
282
+ epicConfig = config.getDefaultConfig();
283
+ }
284
+ const ignoredRules = new Set();
285
+ if (epicConfig.ignore) {
286
+ for (const r of epicConfig.ignore) {
287
+ ignoredRules.add(r.trim());
288
+ }
289
+ }
290
+ if (options.ignore) {
291
+ const cliIgnores = Array.isArray(options.ignore) ? options.ignore : [options.ignore];
292
+ for (const r of cliIgnores) {
293
+ ignoredRules.add(r.trim());
294
+ }
295
+ }
296
+ const activeFindings = findings.filter((f) => !ignoredRules.has(f.rule_id));
297
+ if (options.format === "text") {
298
+ if (activeFindings.length === 0) {
299
+ console.log("No security findings found.");
300
+ }
301
+ else {
302
+ for (const finding of activeFindings) {
303
+ const sevUpper = finding.severity.toUpperCase();
304
+ const relPath = path.relative(process.cwd(), finding.location.file);
305
+ console.log(`${sevUpper} ${finding.rule_id}`);
306
+ console.log(`${relPath}:${finding.location.line}:${finding.location.column}`);
307
+ console.log(`${finding.message}\n`);
308
+ }
309
+ }
310
+ }
311
+ else if (options.format === "json") {
312
+ console.log(JSON.stringify(activeFindings, null, 2));
313
+ }
314
+ else if (options.format === "sarif") {
315
+ const sarif = generateSarif(activeFindings);
316
+ const sarifString = JSON.stringify(sarif, null, 2);
317
+ fs.writeFileSync("sarif.json", sarifString, "utf8");
318
+ console.log(sarifString);
319
+ }
320
+ if (options.strict) {
321
+ const threshold = epicConfig.failOnSeverity || "CRITICAL";
322
+ const thresholdVal = getSeverityLevel(threshold);
323
+ let hasFailingFinding = false;
324
+ for (const finding of activeFindings) {
325
+ const sevVal = getSeverityLevel(finding.severity);
326
+ if (sevVal >= thresholdVal) {
327
+ hasFailingFinding = true;
328
+ break;
329
+ }
330
+ }
331
+ if (hasFailingFinding) {
332
+ process.exit(1);
333
+ }
334
+ else {
335
+ process.exit(0);
336
+ }
337
+ }
338
+ else {
339
+ process.exit(0);
340
+ }
341
+ }
342
+ catch (error) {
343
+ const message = error instanceof Error ? error.message : String(error);
344
+ console.error(`epic audit failed: ${message}`);
345
+ process.exit(1);
346
+ }
347
+ });
348
+ program
349
+ .command("rules")
350
+ .description("List all available security rules.")
351
+ .action(() => {
352
+ console.log("EPIC-SEC-001");
353
+ console.log("Owner Validation");
354
+ console.log("Critical");
355
+ console.log("Implemented\n");
356
+ console.log("EPIC-SEC-002");
357
+ console.log("Missing Signer Validation");
358
+ console.log("Critical");
359
+ console.log("Implemented\n");
360
+ console.log("EPIC-SEC-003");
361
+ console.log("Missing Post-CPI Account Reload");
362
+ console.log("Critical");
363
+ console.log("Implemented\n");
364
+ console.log("EPIC-SEC-004");
365
+ console.log("PDA Cryptographic Seed Collision Risk");
366
+ console.log("High");
367
+ console.log("Implemented\n");
368
+ console.log("EPIC-SEC-005");
369
+ console.log("Arbitrary CPI Target Program Spoofing");
370
+ console.log("Critical");
371
+ console.log("Implemented");
372
+ });
373
+ program
374
+ .command("explain")
375
+ .description("Explain a security rule in detail.")
376
+ .argument("<rule_id>", "Rule ID to explain")
377
+ .action(async (ruleId) => {
378
+ const normRuleId = ruleId.trim().toUpperCase();
379
+ if (normRuleId === "EPIC-SEC-001") {
380
+ let content = "";
381
+ try {
382
+ const docPaths = [
383
+ path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../docs/rules/EPIC-SEC-001.md"),
384
+ path.resolve(process.cwd(), "docs/rules/EPIC-SEC-001.md")
385
+ ];
386
+ for (const p of docPaths) {
387
+ if (fs.existsSync(p)) {
388
+ content = fs.readFileSync(p, "utf8");
389
+ break;
390
+ }
391
+ }
392
+ }
393
+ catch (err) {
394
+ // ignore error
395
+ }
396
+ if (content) {
397
+ console.log(content);
398
+ }
399
+ else {
400
+ console.log(`# EPIC-SEC-001: Owner Validation
401
+
402
+ ## Description
403
+ Tracks mutable account write operations to ensure they are protected by an ownership check (\`account.owner == program_id\`) that dominates the write path.
404
+
405
+ ## Threat Model
406
+ In Solana, any account can be passed to an instruction. If a program writes data to a mutable account without verifying that the account is owned by the program itself, an attacker can pass a forged account with malicious data.
407
+
408
+ ## Vulnerable Example
409
+ \`\`\`rust
410
+ pub fn withdraw(ctx: Context<Withdraw>, amount: u64) -> Result<()> {
411
+ let vault = &mut ctx.accounts.vault;
412
+ let mut vault_data = vault.try_borrow_mut_data()?;
413
+ vault_data[0] = 9;
414
+ Ok(())
415
+ }
416
+ \`\`\`
417
+
418
+ ## Safe Example
419
+ \`\`\`rust
420
+ #[derive(Accounts)]
421
+ pub struct Withdraw<'info> {
422
+ #[account(mut)]
423
+ pub vault: Account<'info, VaultState>,
424
+ }
425
+ \`\`\`
426
+
427
+ ## Historical Exploit References
428
+ * Cashio App ($52M, March 2022)`);
429
+ }
430
+ }
431
+ else if (normRuleId === "EPIC-SEC-002") {
432
+ let content = "";
433
+ try {
434
+ const docPaths = [
435
+ path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../docs/rules/EPIC-SEC-002.md"),
436
+ path.resolve(process.cwd(), "docs/rules/EPIC-SEC-002.md")
437
+ ];
438
+ for (const p of docPaths) {
439
+ if (fs.existsSync(p)) {
440
+ content = fs.readFileSync(p, "utf8");
441
+ break;
442
+ }
443
+ }
444
+ }
445
+ catch (err) {
446
+ // ignore error
447
+ }
448
+ if (content) {
449
+ console.log(content);
450
+ }
451
+ else {
452
+ console.log(`# EPIC-SEC-002: Missing Signer Validation
453
+
454
+ ## Description
455
+ Detects situations where authority-like accounts are capable of mutating state, authorizing actions, or executing privileged flows without proving signer authority.
456
+
457
+ ## Threat Model
458
+ In Solana, callers supply all account inputs. Because any caller can pass arbitrary public keys, the program must verify that the authority-like account signed the transaction. Failing to perform this signer validation allows an attacker to spoof the authority account.
459
+
460
+ ## Vulnerable Example
461
+ \`\`\`rust
462
+ pub fn update_config(ctx: Context<UpdateConfig>, new_val: u64) -> Result<()> {
463
+ ctx.accounts.config.admin_value = new_val;
464
+ Ok(())
465
+ }
466
+ // with authority declared as AccountInfo without Signer constraint
467
+ \`\`\`
468
+
469
+ ## Safe Example
470
+ \`\`\`rust
471
+ pub fn update_config(ctx: Context<UpdateConfig>, new_val: u64) -> Result<()> {
472
+ require!(ctx.accounts.authority.is_signer, ErrorCode::MissingSignature);
473
+ ctx.accounts.config.admin_value = new_val;
474
+ Ok(())
475
+ }
476
+ \`\`\``);
477
+ }
478
+ }
479
+ else if (normRuleId === "EPIC-SEC-003") {
480
+ let content = "";
481
+ try {
482
+ const docPaths = [
483
+ path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../docs/rules/EPIC-SEC-003.md"),
484
+ path.resolve(process.cwd(), "docs/rules/EPIC-SEC-003.md")
485
+ ];
486
+ for (const p of docPaths) {
487
+ if (fs.existsSync(p)) {
488
+ content = fs.readFileSync(p, "utf8");
489
+ break;
490
+ }
491
+ }
492
+ }
493
+ catch (err) {
494
+ // ignore error
495
+ }
496
+ if (content) {
497
+ console.log(content);
498
+ }
499
+ else {
500
+ console.log(`# EPIC-SEC-003: Missing Post-CPI Account Reload
501
+
502
+ ## Description
503
+ Detects scenarios where an account's state data is read or written after a Cross-Program Invocation (CPI) that potentially mutates on-chain state, without executing an intervening reload.
504
+
505
+ ## Threat Model
506
+ In Solana, external programs (like token program or pools) mutate accounts during CPI calls. The local execution context maintains a deserialized in-memory cache of accounts. Calling programs must refresh this cache via \`reload()\` before accessing fields again.
507
+
508
+ ## Vulnerable Example
509
+ \`\`\`rust
510
+ token::transfer(cpi_ctx, amount)?;
511
+ ctx.accounts.vault.amount -= amount; // Stale layout read and write!
512
+ \`\`\`
513
+
514
+ ## Safe Example
515
+ \`\`\`rust
516
+ token::transfer(cpi_ctx, amount)?;
517
+ ctx.accounts.vault.reload()?; // Safe: reload matches state
518
+ ctx.accounts.vault.amount -= amount;
519
+ \`\`\``);
520
+ }
521
+ }
522
+ else if (normRuleId === "EPIC-SEC-004") {
523
+ let content = "";
524
+ try {
525
+ const docPaths = [
526
+ path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../docs/rules/EPIC-SEC-004.md"),
527
+ path.resolve(process.cwd(), "docs/rules/EPIC-SEC-004.md")
528
+ ];
529
+ for (const p of docPaths) {
530
+ if (fs.existsSync(p)) {
531
+ content = fs.readFileSync(p, "utf8");
532
+ break;
533
+ }
534
+ }
535
+ }
536
+ catch (err) {
537
+ // ignore error
538
+ }
539
+ if (content) {
540
+ console.log(content);
541
+ }
542
+ else {
543
+ console.log(`# EPIC-SEC-004: PDA Cryptographic Seed Collision Risk
544
+
545
+ ## Description
546
+ Detects scenarios where adjacent variable-length seeds in Program Derived Address (PDA) derivation can merge boundaries, allowing an attacker to generate the same address from two different inputs.
547
+
548
+ ## Threat Model
549
+ In Solana, PDAs are derived by concatenating the raw seed bytes without adding delimiters. When two variable-length seeds (like strings or dynamic byte arrays) are placed next to each other, boundary bytes can shift between seeds while keeping the concatenated byte stream identical.
550
+
551
+ ## Vulnerable Example
552
+ \`\`\`rust
553
+ Pubkey::find_program_address(
554
+ &[
555
+ user_name.as_bytes(),
556
+ folder_name.as_bytes(),
557
+ ],
558
+ program_id,
559
+ );
560
+ \`\`\`
561
+
562
+ ## Safe Example
563
+ \`\`\`rust
564
+ Pubkey::find_program_address(
565
+ &[
566
+ user_name.as_bytes(),
567
+ b"|",
568
+ folder_name.as_bytes(),
569
+ ],
570
+ program_id,
571
+ );
572
+ \`\`\``);
573
+ }
574
+ }
575
+ else if (normRuleId === "EPIC-SEC-005") {
576
+ let content = "";
577
+ try {
578
+ const docPaths = [
579
+ path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../docs/rules/EPIC-SEC-005.md"),
580
+ path.resolve(process.cwd(), "docs/rules/EPIC-SEC-005.md")
581
+ ];
582
+ for (const p of docPaths) {
583
+ if (fs.existsSync(p)) {
584
+ content = fs.readFileSync(p, "utf8");
585
+ break;
586
+ }
587
+ }
588
+ }
589
+ catch (err) {
590
+ // ignore error
591
+ }
592
+ if (content) {
593
+ console.log(content);
594
+ }
595
+ else {
596
+ console.log(`# EPIC-SEC-005: Arbitrary CPI Target Program Spoofing
597
+
598
+ ## Description
599
+ Detects scenarios where a program invokes another program via CPI without verifying that the target program matches a trusted program ID.
600
+
601
+ ## Threat Model
602
+ In Solana, callers supply all input accounts, including the program being invoked. If the program fails to verify that the target program account is trusted, an attacker can pass a custom malicious program and hijack control flow under the PDA authority of the program.
603
+
604
+ ## Vulnerable Example
605
+ \`\`\`rust
606
+ invoke(&ix, &[source, dest, token_program])?; // token_program is not validated!
607
+ \`\`\`
608
+
609
+ ## Safe Example
610
+ \`\`\`rust
611
+ require_keys_eq!(token_program.key(), token::ID);
612
+ invoke(&ix, &[source, dest, token_program])?;
613
+ \`\`\``);
614
+ }
615
+ }
616
+ else {
617
+ console.log(`Rule ${ruleId} not found.`);
618
+ process.exit(1);
619
+ }
620
+ });
621
+ program.parse(process.argv);
622
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export declare class EPICBinaryNotFoundError extends Error {
2
+ constructor(platform: string, arch: string, attemptedLocations: string[]);
3
+ }
4
+ /**
5
+ * Returns the detected platform key (e.g. "darwin-arm64").
6
+ */
7
+ export declare function getPlatformKey(platform?: NodeJS.Platform, arch?: NodeJS.Architecture): string;
8
+ /**
9
+ * Resolves the absolute path to the parser-v2 Rust compiled binary.
10
+ */
11
+ export declare function resolveParserBinary(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform, arch?: NodeJS.Architecture, importMetaUrl?: string): string;
12
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAYA,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE;CAWzE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,kBAAmB,EAAE,IAAI,sBAAe,GAAG,MAAM,CAEvF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,oBAAc,EACjB,QAAQ,kBAAmB,EAC3B,IAAI,sBAAe,EACnB,aAAa,SAAkB,GAC9B,MAAM,CA0ER"}
package/dist/loader.js ADDED
@@ -0,0 +1,107 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs";
3
+ import process from "node:process";
4
+ import { fileURLToPath } from "node:url";
5
+ const PLATFORM_MAP = {
6
+ "darwin-arm64": "@solana-epic/cli-darwin-arm64",
7
+ "darwin-x64": "@solana-epic/cli-darwin-x64",
8
+ "linux-x64": "@solana-epic/cli-linux-x64",
9
+ "win32-x64": "@solana-epic/cli-win32-x64"
10
+ };
11
+ export class EPICBinaryNotFoundError extends Error {
12
+ constructor(platform, arch, attemptedLocations) {
13
+ const message = [
14
+ `EPIC Upgrade Guard parser-v2 binary not found.`,
15
+ `Current Platform: ${platform}`,
16
+ `Current Architecture: ${arch}`,
17
+ `Attempted Locations:`,
18
+ ...attemptedLocations.map(loc => ` - ${loc}`)
19
+ ].join("\n");
20
+ super(message);
21
+ this.name = "EPICBinaryNotFoundError";
22
+ }
23
+ }
24
+ /**
25
+ * Returns the detected platform key (e.g. "darwin-arm64").
26
+ */
27
+ export function getPlatformKey(platform = process.platform, arch = process.arch) {
28
+ return `${platform}-${arch}`;
29
+ }
30
+ /**
31
+ * Resolves the absolute path to the parser-v2 Rust compiled binary.
32
+ */
33
+ export function resolveParserBinary(env = process.env, platform = process.platform, arch = process.arch, importMetaUrl = import.meta.url) {
34
+ const platformKey = getPlatformKey(platform, arch);
35
+ const packageName = PLATFORM_MAP[platformKey];
36
+ const binName = platform === "win32" ? "parser-v2.exe" : "parser-v2";
37
+ const attempted = [];
38
+ // 1. Attempt package resolve from dependencies/optionalDependencies
39
+ if (packageName) {
40
+ try {
41
+ const resolvedUrl = import.meta.resolve(packageName);
42
+ const resolvedPath = fileURLToPath(resolvedUrl);
43
+ attempted.push(`NPM Package (${packageName}) -> ${resolvedPath}`);
44
+ if (fs.existsSync(resolvedPath)) {
45
+ return resolvedPath;
46
+ }
47
+ }
48
+ catch {
49
+ attempted.push(`NPM Package (${packageName}) -> Not installed / Resolution failed`);
50
+ // Local development fallback for packages when not installed/linked in monorepo
51
+ try {
52
+ const __dirname = path.dirname(fileURLToPath(importMetaUrl));
53
+ const localPackagePath = path.resolve(__dirname, "../..", packageName.split("/")[1], "bin", binName);
54
+ attempted.push(`Local Monorepo Package Fallback (${packageName}) -> ${localPackagePath}`);
55
+ if (fs.existsSync(localPackagePath)) {
56
+ return localPackagePath;
57
+ }
58
+ }
59
+ catch { }
60
+ }
61
+ }
62
+ else {
63
+ attempted.push(`NPM Package -> Unsupported platform key: ${platformKey}`);
64
+ }
65
+ // 2. Attempt local development compilation fallback
66
+ try {
67
+ const __dirname = path.dirname(fileURLToPath(importMetaUrl));
68
+ const localPaths = [
69
+ path.resolve(__dirname, "../../parser-v2/target/release", binName),
70
+ path.resolve(__dirname, "../../parser-v2/target/debug", binName),
71
+ path.resolve(__dirname, "../../../parser-v2/target/release", binName),
72
+ path.resolve(__dirname, "../../../parser-v2/target/debug", binName)
73
+ ];
74
+ for (const localPath of localPaths) {
75
+ attempted.push(`Local Dev Target -> ${localPath}`);
76
+ if (fs.existsSync(localPath)) {
77
+ return localPath;
78
+ }
79
+ }
80
+ }
81
+ catch {
82
+ attempted.push(`Local Dev Target -> Directory lookup context failed`);
83
+ }
84
+ // 3. Attempt PATH environment traversal lookup
85
+ const pathEnv = env.PATH || "";
86
+ const pathDirs = pathEnv.split(path.delimiter);
87
+ attempted.push(`PATH Lookup -> Scanning ${pathDirs.length} path directories`);
88
+ for (const dir of pathDirs) {
89
+ if (!dir)
90
+ continue;
91
+ const candidatePath = path.join(dir, binName);
92
+ if (fs.existsSync(candidatePath)) {
93
+ try {
94
+ // Simple Windows sanity check (Windows has no X_OK, check exists is sufficient)
95
+ if (platform !== "win32") {
96
+ fs.accessSync(candidatePath, fs.constants.X_OK);
97
+ }
98
+ return candidatePath;
99
+ }
100
+ catch {
101
+ // Exists but not executable
102
+ }
103
+ }
104
+ }
105
+ throw new EPICBinaryNotFoundError(platform, arch, attempted);
106
+ }
107
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@solana-epic/cli",
3
+ "version": "0.1.0-beta.1",
4
+ "private": false,
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "type": "module",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "bin": {
13
+ "epic": "./dist/index.js"
14
+ },
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "scripts": {
18
+ "build": "tsc -p tsconfig.json",
19
+ "check": "tsc -p tsconfig.json --noEmit",
20
+ "dev": "tsx src/index.ts",
21
+ "test": "node --test test/*.test.mjs"
22
+ },
23
+ "dependencies": {
24
+ "@solana-epic/diff-engine": "^0.1.0-beta.1",
25
+ "@solana-epic/parser": "^0.1.0-beta.1",
26
+ "commander": "^14.0.0"
27
+ },
28
+ "optionalDependencies": {
29
+ "@solana-epic/cli-darwin-arm64": "^0.1.0-beta.1",
30
+ "@solana-epic/cli-darwin-x64": "^0.1.0-beta.1",
31
+ "@solana-epic/cli-linux-x64": "^0.1.0-beta.1",
32
+ "@solana-epic/cli-win32-x64": "^0.1.0-beta.1"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^22.15.29",
36
+ "tsx": "^4.19.4"
37
+ }
38
+ }