@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.
- package/dist/benchmark.d.ts +2 -0
- package/dist/benchmark.d.ts.map +1 -0
- package/dist/benchmark.js +344 -0
- package/dist/benchmark.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +622 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +12 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +107 -0
- package/dist/loader.js.map +1 -0
- package/package.json +38 -0
|
@@ -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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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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"}
|
package/dist/loader.d.ts
ADDED
|
@@ -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
|
+
}
|