windows-exe-decompiler-mcp-server 0.1.0

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.
Files changed (190) hide show
  1. package/CODEX_INSTALLATION.md +69 -0
  2. package/COPILOT_INSTALLATION.md +77 -0
  3. package/LICENSE +21 -0
  4. package/README.md +314 -0
  5. package/bin/windows-exe-decompiler-mcp-server.js +3 -0
  6. package/dist/analysis-provenance.d.ts +184 -0
  7. package/dist/analysis-provenance.js +74 -0
  8. package/dist/analysis-task-runner.d.ts +31 -0
  9. package/dist/analysis-task-runner.js +160 -0
  10. package/dist/artifact-inventory.d.ts +23 -0
  11. package/dist/artifact-inventory.js +175 -0
  12. package/dist/cache-manager.d.ts +128 -0
  13. package/dist/cache-manager.js +454 -0
  14. package/dist/confidence-semantics.d.ts +66 -0
  15. package/dist/confidence-semantics.js +122 -0
  16. package/dist/config.d.ts +335 -0
  17. package/dist/config.js +193 -0
  18. package/dist/database.d.ts +227 -0
  19. package/dist/database.js +601 -0
  20. package/dist/decompiler-worker.d.ts +441 -0
  21. package/dist/decompiler-worker.js +1962 -0
  22. package/dist/dynamic-trace.d.ts +95 -0
  23. package/dist/dynamic-trace.js +629 -0
  24. package/dist/env-validator.d.ts +15 -0
  25. package/dist/env-validator.js +249 -0
  26. package/dist/error-handler.d.ts +28 -0
  27. package/dist/error-handler.example.d.ts +22 -0
  28. package/dist/error-handler.example.js +141 -0
  29. package/dist/error-handler.js +139 -0
  30. package/dist/ghidra-analysis-status.d.ts +49 -0
  31. package/dist/ghidra-analysis-status.js +178 -0
  32. package/dist/ghidra-config.d.ts +134 -0
  33. package/dist/ghidra-config.js +464 -0
  34. package/dist/index.d.ts +9 -0
  35. package/dist/index.js +200 -0
  36. package/dist/job-queue.d.ts +169 -0
  37. package/dist/job-queue.js +407 -0
  38. package/dist/logger.d.ts +106 -0
  39. package/dist/logger.js +176 -0
  40. package/dist/policy-guard.d.ts +115 -0
  41. package/dist/policy-guard.js +243 -0
  42. package/dist/process-output.d.ts +15 -0
  43. package/dist/process-output.js +90 -0
  44. package/dist/prompts/function-explanation-review.d.ts +5 -0
  45. package/dist/prompts/function-explanation-review.js +64 -0
  46. package/dist/prompts/semantic-name-review.d.ts +5 -0
  47. package/dist/prompts/semantic-name-review.js +63 -0
  48. package/dist/runtime-correlation.d.ts +34 -0
  49. package/dist/runtime-correlation.js +279 -0
  50. package/dist/runtime-paths.d.ts +3 -0
  51. package/dist/runtime-paths.js +11 -0
  52. package/dist/selection-diff.d.ts +667 -0
  53. package/dist/selection-diff.js +53 -0
  54. package/dist/semantic-name-suggestion-artifacts.d.ts +116 -0
  55. package/dist/semantic-name-suggestion-artifacts.js +314 -0
  56. package/dist/server.d.ts +129 -0
  57. package/dist/server.js +578 -0
  58. package/dist/tools/artifact-read.d.ts +235 -0
  59. package/dist/tools/artifact-read.js +317 -0
  60. package/dist/tools/artifacts-diff.d.ts +728 -0
  61. package/dist/tools/artifacts-diff.js +304 -0
  62. package/dist/tools/artifacts-list.d.ts +515 -0
  63. package/dist/tools/artifacts-list.js +389 -0
  64. package/dist/tools/attack-map.d.ts +290 -0
  65. package/dist/tools/attack-map.js +519 -0
  66. package/dist/tools/cache-observability.d.ts +4 -0
  67. package/dist/tools/cache-observability.js +36 -0
  68. package/dist/tools/code-function-cfg.d.ts +50 -0
  69. package/dist/tools/code-function-cfg.js +102 -0
  70. package/dist/tools/code-function-decompile.d.ts +55 -0
  71. package/dist/tools/code-function-decompile.js +103 -0
  72. package/dist/tools/code-function-disassemble.d.ts +43 -0
  73. package/dist/tools/code-function-disassemble.js +185 -0
  74. package/dist/tools/code-function-explain-apply.d.ts +255 -0
  75. package/dist/tools/code-function-explain-apply.js +225 -0
  76. package/dist/tools/code-function-explain-prepare.d.ts +535 -0
  77. package/dist/tools/code-function-explain-prepare.js +276 -0
  78. package/dist/tools/code-function-explain-review.d.ts +397 -0
  79. package/dist/tools/code-function-explain-review.js +589 -0
  80. package/dist/tools/code-function-rename-apply.d.ts +248 -0
  81. package/dist/tools/code-function-rename-apply.js +220 -0
  82. package/dist/tools/code-function-rename-prepare.d.ts +506 -0
  83. package/dist/tools/code-function-rename-prepare.js +279 -0
  84. package/dist/tools/code-function-rename-review.d.ts +574 -0
  85. package/dist/tools/code-function-rename-review.js +761 -0
  86. package/dist/tools/code-functions-list.d.ts +37 -0
  87. package/dist/tools/code-functions-list.js +91 -0
  88. package/dist/tools/code-functions-rank.d.ts +34 -0
  89. package/dist/tools/code-functions-rank.js +90 -0
  90. package/dist/tools/code-functions-reconstruct.d.ts +2725 -0
  91. package/dist/tools/code-functions-reconstruct.js +2807 -0
  92. package/dist/tools/code-functions-search.d.ts +39 -0
  93. package/dist/tools/code-functions-search.js +90 -0
  94. package/dist/tools/code-reconstruct-export.d.ts +1212 -0
  95. package/dist/tools/code-reconstruct-export.js +4002 -0
  96. package/dist/tools/code-reconstruct-plan.d.ts +274 -0
  97. package/dist/tools/code-reconstruct-plan.js +342 -0
  98. package/dist/tools/dotnet-metadata-extract.d.ts +541 -0
  99. package/dist/tools/dotnet-metadata-extract.js +355 -0
  100. package/dist/tools/dotnet-reconstruct-export.d.ts +567 -0
  101. package/dist/tools/dotnet-reconstruct-export.js +1151 -0
  102. package/dist/tools/dotnet-types-list.d.ts +325 -0
  103. package/dist/tools/dotnet-types-list.js +201 -0
  104. package/dist/tools/dynamic-dependencies.d.ts +115 -0
  105. package/dist/tools/dynamic-dependencies.js +213 -0
  106. package/dist/tools/dynamic-memory-import.d.ts +10 -0
  107. package/dist/tools/dynamic-memory-import.js +567 -0
  108. package/dist/tools/dynamic-trace-import.d.ts +10 -0
  109. package/dist/tools/dynamic-trace-import.js +235 -0
  110. package/dist/tools/entrypoint-fallback-disasm.d.ts +30 -0
  111. package/dist/tools/entrypoint-fallback-disasm.js +89 -0
  112. package/dist/tools/ghidra-analyze.d.ts +88 -0
  113. package/dist/tools/ghidra-analyze.js +208 -0
  114. package/dist/tools/ghidra-health.d.ts +37 -0
  115. package/dist/tools/ghidra-health.js +212 -0
  116. package/dist/tools/ioc-export.d.ts +209 -0
  117. package/dist/tools/ioc-export.js +542 -0
  118. package/dist/tools/packer-detect.d.ts +165 -0
  119. package/dist/tools/packer-detect.js +284 -0
  120. package/dist/tools/pe-exports-extract.d.ts +175 -0
  121. package/dist/tools/pe-exports-extract.js +253 -0
  122. package/dist/tools/pe-fingerprint.d.ts +234 -0
  123. package/dist/tools/pe-fingerprint.js +269 -0
  124. package/dist/tools/pe-imports-extract.d.ts +105 -0
  125. package/dist/tools/pe-imports-extract.js +245 -0
  126. package/dist/tools/report-generate.d.ts +157 -0
  127. package/dist/tools/report-generate.js +457 -0
  128. package/dist/tools/report-summarize.d.ts +2131 -0
  129. package/dist/tools/report-summarize.js +596 -0
  130. package/dist/tools/runtime-detect.d.ts +135 -0
  131. package/dist/tools/runtime-detect.js +247 -0
  132. package/dist/tools/sample-ingest.d.ts +94 -0
  133. package/dist/tools/sample-ingest.js +327 -0
  134. package/dist/tools/sample-profile-get.d.ts +183 -0
  135. package/dist/tools/sample-profile-get.js +121 -0
  136. package/dist/tools/sandbox-execute.d.ts +441 -0
  137. package/dist/tools/sandbox-execute.js +392 -0
  138. package/dist/tools/strings-extract.d.ts +375 -0
  139. package/dist/tools/strings-extract.js +314 -0
  140. package/dist/tools/strings-floss-decode.d.ts +143 -0
  141. package/dist/tools/strings-floss-decode.js +259 -0
  142. package/dist/tools/system-health.d.ts +434 -0
  143. package/dist/tools/system-health.js +446 -0
  144. package/dist/tools/task-cancel.d.ts +21 -0
  145. package/dist/tools/task-cancel.js +70 -0
  146. package/dist/tools/task-status.d.ts +27 -0
  147. package/dist/tools/task-status.js +106 -0
  148. package/dist/tools/task-sweep.d.ts +22 -0
  149. package/dist/tools/task-sweep.js +77 -0
  150. package/dist/tools/tool-help.d.ts +340 -0
  151. package/dist/tools/tool-help.js +261 -0
  152. package/dist/tools/yara-scan.d.ts +554 -0
  153. package/dist/tools/yara-scan.js +313 -0
  154. package/dist/types.d.ts +266 -0
  155. package/dist/types.js +41 -0
  156. package/dist/worker-pool.d.ts +204 -0
  157. package/dist/worker-pool.js +650 -0
  158. package/dist/workflows/deep-static.d.ts +104 -0
  159. package/dist/workflows/deep-static.js +276 -0
  160. package/dist/workflows/function-explanation-review.d.ts +655 -0
  161. package/dist/workflows/function-explanation-review.js +440 -0
  162. package/dist/workflows/reconstruct.d.ts +2053 -0
  163. package/dist/workflows/reconstruct.js +666 -0
  164. package/dist/workflows/semantic-name-review.d.ts +2418 -0
  165. package/dist/workflows/semantic-name-review.js +521 -0
  166. package/dist/workflows/triage.d.ts +659 -0
  167. package/dist/workflows/triage.js +1374 -0
  168. package/dist/workspace-manager.d.ts +150 -0
  169. package/dist/workspace-manager.js +411 -0
  170. package/ghidra_scripts/DecompileFunction.java +487 -0
  171. package/ghidra_scripts/DecompileFunction.py +150 -0
  172. package/ghidra_scripts/ExtractCFG.java +256 -0
  173. package/ghidra_scripts/ExtractCFG.py +233 -0
  174. package/ghidra_scripts/ExtractFunctions.java +442 -0
  175. package/ghidra_scripts/ExtractFunctions.py +101 -0
  176. package/ghidra_scripts/README.md +125 -0
  177. package/ghidra_scripts/SearchFunctionReferences.java +380 -0
  178. package/helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj +9 -0
  179. package/helpers/DotNetMetadataProbe/Program.cs +566 -0
  180. package/install-to-codex.ps1 +178 -0
  181. package/install-to-copilot.ps1 +303 -0
  182. package/package.json +101 -0
  183. package/requirements.txt +9 -0
  184. package/workers/requirements-dynamic.txt +11 -0
  185. package/workers/requirements.txt +8 -0
  186. package/workers/speakeasy_compat.py +175 -0
  187. package/workers/static_worker.py +5183 -0
  188. package/workers/yara_rules/default.yar +33 -0
  189. package/workers/yara_rules/malware_families.yar +93 -0
  190. package/workers/yara_rules/packers.yar +80 -0
@@ -0,0 +1,454 @@
1
+ /**
2
+ * Cache Manager
3
+ * Implements cache key generation and three-tier caching architecture
4
+ * Requirements: 20.1, 20.2, 20.3, 20.4, 20.5
5
+ */
6
+ import crypto from 'crypto';
7
+ import fs from 'fs/promises';
8
+ import path from 'path';
9
+ /**
10
+ * LRU Cache implementation for memory caching
11
+ */
12
+ class LRUCache {
13
+ cache;
14
+ maxSize;
15
+ ttlMs;
16
+ constructor(maxSize, ttlMs) {
17
+ this.cache = new Map();
18
+ this.maxSize = maxSize;
19
+ this.ttlMs = ttlMs;
20
+ }
21
+ getWithMeta(key) {
22
+ const entry = this.cache.get(key);
23
+ if (!entry)
24
+ return null;
25
+ const now = Date.now();
26
+ // Check if expired
27
+ if (now - entry.insertedAt > this.ttlMs) {
28
+ this.cache.delete(key);
29
+ return null;
30
+ }
31
+ // Check absolute source expiration (if available)
32
+ if (entry.expiresAtMs && now > entry.expiresAtMs) {
33
+ this.cache.delete(key);
34
+ return null;
35
+ }
36
+ // Move to end (most recently used)
37
+ this.cache.delete(key);
38
+ this.cache.set(key, entry);
39
+ return {
40
+ value: entry.value,
41
+ createdAt: entry.createdAt,
42
+ expiresAt: entry.expiresAt,
43
+ sampleSha256: entry.sampleSha256,
44
+ };
45
+ }
46
+ get(key) {
47
+ const entry = this.getWithMeta(key);
48
+ if (!entry) {
49
+ return null;
50
+ }
51
+ return entry.value;
52
+ }
53
+ set(key, value, options) {
54
+ // Remove if exists (to update position)
55
+ this.cache.delete(key);
56
+ // Evict oldest if at capacity
57
+ if (this.cache.size >= this.maxSize) {
58
+ const firstKey = this.cache.keys().next().value;
59
+ if (firstKey) {
60
+ this.cache.delete(firstKey);
61
+ }
62
+ }
63
+ const createdAt = options?.createdAt || new Date().toISOString();
64
+ const expiresAt = options?.expiresAt;
65
+ const expiresAtMs = expiresAt ? new Date(expiresAt).getTime() : undefined;
66
+ this.cache.set(key, {
67
+ value,
68
+ insertedAt: Date.now(),
69
+ createdAt,
70
+ expiresAt,
71
+ expiresAtMs: Number.isNaN(expiresAtMs) ? undefined : expiresAtMs,
72
+ sampleSha256: options?.sampleSha256,
73
+ });
74
+ }
75
+ clear() {
76
+ this.cache.clear();
77
+ }
78
+ }
79
+ /**
80
+ * File System Cache implementation
81
+ */
82
+ class FileSystemCache {
83
+ cacheDir;
84
+ ttlMs;
85
+ constructor(cacheDir, ttlMs) {
86
+ this.cacheDir = cacheDir;
87
+ this.ttlMs = ttlMs;
88
+ }
89
+ getCachePath(key) {
90
+ // Use first 2 chars for bucketing to avoid too many files in one directory
91
+ const bucket = key.substring(6, 8); // Skip "cache:" prefix
92
+ return path.join(this.cacheDir, bucket, `${key}.json`);
93
+ }
94
+ async getWithMeta(key) {
95
+ try {
96
+ const cachePath = this.getCachePath(key);
97
+ const content = await fs.readFile(cachePath, 'utf-8');
98
+ const cached = JSON.parse(content);
99
+ // Check if expired
100
+ if (cached.expiresAt && new Date(cached.expiresAt) < new Date()) {
101
+ await fs.unlink(cachePath).catch(() => { }); // Ignore errors
102
+ return null;
103
+ }
104
+ return {
105
+ data: cached.data,
106
+ createdAt: cached.createdAt,
107
+ expiresAt: cached.expiresAt,
108
+ sampleSha256: cached.sampleSha256,
109
+ };
110
+ }
111
+ catch (error) {
112
+ // File doesn't exist or can't be read
113
+ return null;
114
+ }
115
+ }
116
+ async get(key) {
117
+ const cached = await this.getWithMeta(key);
118
+ if (!cached) {
119
+ return null;
120
+ }
121
+ return cached.data;
122
+ }
123
+ async set(key, data, ttlMs, sampleSha256) {
124
+ try {
125
+ const cachePath = this.getCachePath(key);
126
+ const cacheDir = path.dirname(cachePath);
127
+ // Ensure directory exists
128
+ await fs.mkdir(cacheDir, { recursive: true });
129
+ const cached = {
130
+ key,
131
+ data,
132
+ createdAt: new Date().toISOString(),
133
+ expiresAt: new Date(Date.now() + (ttlMs || this.ttlMs)).toISOString(),
134
+ sampleSha256,
135
+ };
136
+ await fs.writeFile(cachePath, JSON.stringify(cached), 'utf-8');
137
+ }
138
+ catch (error) {
139
+ // Ignore write errors (cache is optional)
140
+ console.warn(`Failed to write cache to filesystem: ${error}`);
141
+ }
142
+ }
143
+ }
144
+ /**
145
+ * Cache Manager with three-tier architecture
146
+ *
147
+ * Requirements: 20.3, 20.4, 20.5, 26.1 (cache prewarming)
148
+ *
149
+ * Architecture:
150
+ * - L1: Memory cache (LRU, 5 minutes TTL)
151
+ * - L2: File system cache (30 days TTL)
152
+ * - L3: Database cache
153
+ */
154
+ export class CacheManager {
155
+ memoryCache;
156
+ fsCache;
157
+ db;
158
+ prewarmInProgress = false;
159
+ constructor(cacheDir, db) {
160
+ // L1: Memory cache - 1000 items, 5 minutes TTL
161
+ this.memoryCache = new LRUCache(1000, 5 * 60 * 1000);
162
+ // L2: File system cache - 30 days TTL
163
+ this.fsCache = new FileSystemCache(cacheDir, 30 * 24 * 60 * 60 * 1000);
164
+ // L3: Database cache (optional)
165
+ this.db = db || null;
166
+ }
167
+ /**
168
+ * Get cached result from three-tier cache
169
+ *
170
+ * Requirements: 20.3
171
+ *
172
+ * Algorithm:
173
+ * 1. Check L1 (memory cache)
174
+ * 2. If miss, check L2 (file system cache) and populate L1
175
+ * 3. If miss, check L3 (database cache) and populate L1 and L2
176
+ * 4. Return null if not found in any layer
177
+ *
178
+ * @param key - Cache key
179
+ * @returns Cached data or null if not found
180
+ */
181
+ async getCachedResult(key) {
182
+ const cached = await this.getCachedResultWithMetadata(key);
183
+ return cached?.data ?? null;
184
+ }
185
+ /**
186
+ * Get cached result with hit metadata for observability.
187
+ */
188
+ async getCachedResultWithMetadata(key) {
189
+ // L1: Check memory cache
190
+ const memoryResult = this.memoryCache.getWithMeta(key);
191
+ if (memoryResult !== null) {
192
+ return {
193
+ data: memoryResult.value,
194
+ metadata: {
195
+ key,
196
+ tier: 'memory',
197
+ createdAt: memoryResult.createdAt,
198
+ expiresAt: memoryResult.expiresAt,
199
+ fetchedAt: new Date().toISOString(),
200
+ sampleSha256: memoryResult.sampleSha256,
201
+ },
202
+ };
203
+ }
204
+ // L2: Check file system cache
205
+ const fsResult = await this.fsCache.getWithMeta(key);
206
+ if (fsResult !== null) {
207
+ // Populate L1
208
+ this.memoryCache.set(key, fsResult.data, {
209
+ createdAt: fsResult.createdAt,
210
+ expiresAt: fsResult.expiresAt,
211
+ sampleSha256: fsResult.sampleSha256,
212
+ });
213
+ return {
214
+ data: fsResult.data,
215
+ metadata: {
216
+ key,
217
+ tier: 'filesystem',
218
+ createdAt: fsResult.createdAt,
219
+ expiresAt: fsResult.expiresAt,
220
+ fetchedAt: new Date().toISOString(),
221
+ sampleSha256: fsResult.sampleSha256,
222
+ },
223
+ };
224
+ }
225
+ // L3: Check database cache
226
+ if (this.db) {
227
+ const cached = await this.db.getCachedResult(key);
228
+ if (cached) {
229
+ // Check if expired
230
+ if (cached.expiresAt && new Date(cached.expiresAt) < new Date()) {
231
+ return null;
232
+ }
233
+ let remainingTtlMs;
234
+ if (cached.expiresAt) {
235
+ const remaining = new Date(cached.expiresAt).getTime() - Date.now();
236
+ if (remaining > 0) {
237
+ remainingTtlMs = remaining;
238
+ }
239
+ }
240
+ // Populate L1 and L2
241
+ this.memoryCache.set(key, cached.data, {
242
+ createdAt: cached.createdAt,
243
+ expiresAt: cached.expiresAt,
244
+ sampleSha256: cached.sampleSha256,
245
+ });
246
+ await this.fsCache.set(key, cached.data, remainingTtlMs, cached.sampleSha256);
247
+ return {
248
+ data: cached.data,
249
+ metadata: {
250
+ key,
251
+ tier: 'database',
252
+ createdAt: cached.createdAt,
253
+ expiresAt: cached.expiresAt,
254
+ fetchedAt: new Date().toISOString(),
255
+ sampleSha256: cached.sampleSha256,
256
+ },
257
+ };
258
+ }
259
+ }
260
+ return null;
261
+ }
262
+ /**
263
+ * Set cached result in all three tiers
264
+ *
265
+ * Requirements: 20.4
266
+ *
267
+ * Algorithm:
268
+ * 1. Store in L1 (memory cache)
269
+ * 2. Store in L2 (file system cache)
270
+ * 3. Store in L3 (database cache) if available
271
+ *
272
+ * @param key - Cache key
273
+ * @param data - Data to cache
274
+ * @param ttl - Time to live in milliseconds (optional)
275
+ */
276
+ async setCachedResult(key, data, ttl, sampleSha256) {
277
+ // L1: Store in memory cache
278
+ this.memoryCache.set(key, data, { sampleSha256 });
279
+ // L2: Store in file system cache
280
+ await this.fsCache.set(key, data, ttl, sampleSha256);
281
+ // L3: Store in database cache
282
+ if (this.db) {
283
+ const expiresAt = ttl ? new Date(Date.now() + ttl).toISOString() : undefined;
284
+ await this.db.setCachedResult(key, data, expiresAt, sampleSha256);
285
+ }
286
+ }
287
+ /**
288
+ * Clear all caches
289
+ */
290
+ clearAll() {
291
+ this.memoryCache.clear();
292
+ }
293
+ /**
294
+ * Prewarm cache by loading frequently accessed data into memory
295
+ *
296
+ * Requirements: 26.1 (cache prewarming)
297
+ *
298
+ * Strategy:
299
+ * 1. Load recent cache entries from database
300
+ * 2. Populate L1 (memory) and L2 (filesystem) caches
301
+ * 3. Prioritize entries with high access frequency
302
+ *
303
+ * @param maxEntries - Maximum number of entries to prewarm (default: 100)
304
+ */
305
+ async prewarmCache(maxEntries = 100) {
306
+ if (this.prewarmInProgress) {
307
+ return 0; // Already prewarming
308
+ }
309
+ this.prewarmInProgress = true;
310
+ let prewarmedCount = 0;
311
+ try {
312
+ if (!this.db) {
313
+ return 0; // No database to prewarm from
314
+ }
315
+ // Get recent cache entries from database
316
+ const recentEntries = await this.db.getRecentCacheEntries(maxEntries);
317
+ // Load into memory and filesystem caches
318
+ for (const entry of recentEntries) {
319
+ try {
320
+ // Skip expired entries
321
+ if (entry.expires_at && new Date(entry.expires_at) < new Date()) {
322
+ continue;
323
+ }
324
+ // Parse data
325
+ const data = JSON.parse(entry.data);
326
+ // Populate L1 (memory cache)
327
+ this.memoryCache.set(entry.key, data);
328
+ // Populate L2 (filesystem cache) - async, don't wait
329
+ this.fsCache.set(entry.key, data).catch(() => {
330
+ // Ignore filesystem errors during prewarming
331
+ });
332
+ prewarmedCount++;
333
+ }
334
+ catch (error) {
335
+ // Skip invalid entries
336
+ continue;
337
+ }
338
+ }
339
+ return prewarmedCount;
340
+ }
341
+ finally {
342
+ this.prewarmInProgress = false;
343
+ }
344
+ }
345
+ /**
346
+ * Prewarm cache for a specific sample
347
+ * Loads all cached results for a sample into memory
348
+ *
349
+ * Requirements: 26.1 (cache prewarming)
350
+ *
351
+ * @param sampleSha256 - SHA256 hash of the sample
352
+ * @returns Number of entries prewarmed
353
+ */
354
+ async prewarmSampleCache(sampleSha256) {
355
+ if (!this.db) {
356
+ return 0;
357
+ }
358
+ let prewarmedCount = 0;
359
+ // Get all cache entries for this sample
360
+ const sampleEntries = await this.db.getCacheEntriesBySample(sampleSha256);
361
+ for (const entry of sampleEntries) {
362
+ try {
363
+ // Skip expired entries
364
+ if (entry.expires_at && new Date(entry.expires_at) < new Date()) {
365
+ continue;
366
+ }
367
+ // Parse data
368
+ const data = JSON.parse(entry.data);
369
+ // Populate L1 (memory cache)
370
+ this.memoryCache.set(entry.key, data);
371
+ prewarmedCount++;
372
+ }
373
+ catch (error) {
374
+ // Skip invalid entries
375
+ continue;
376
+ }
377
+ }
378
+ return prewarmedCount;
379
+ }
380
+ }
381
+ /**
382
+ * Generate deterministic cache key from parameters
383
+ *
384
+ * Requirements: 20.1, 20.2
385
+ *
386
+ * Algorithm:
387
+ * 1. Normalize arguments (sort keys, remove defaults)
388
+ * 2. Create canonical representation
389
+ * 3. Generate SHA256 hash
390
+ *
391
+ * @param params - Cache key parameters
392
+ * @returns Cache key string in format "cache:<sha256>"
393
+ */
394
+ export function generateCacheKey(params) {
395
+ // Create normalized object with sorted keys
396
+ const normalized = {
397
+ sampleSha256: params.sampleSha256,
398
+ toolName: params.toolName,
399
+ toolVersion: params.toolVersion,
400
+ args: normalizeArgs(params.args),
401
+ ...(params.rulesetVersion && { rulesetVersion: params.rulesetVersion })
402
+ };
403
+ // Sort keys at top level to ensure deterministic order
404
+ const sortedKeys = Object.keys(normalized).sort();
405
+ const sortedNormalized = sortedKeys.reduce((acc, key) => {
406
+ acc[key] = normalized[key];
407
+ return acc;
408
+ }, {});
409
+ // Generate canonical JSON string
410
+ const keyString = JSON.stringify(sortedNormalized);
411
+ // Generate SHA256 hash
412
+ const hash = crypto.createHash('sha256').update(keyString).digest('hex');
413
+ return `cache:${hash}`;
414
+ }
415
+ /**
416
+ * Normalize arguments for cache key generation
417
+ *
418
+ * Requirements: 20.2
419
+ *
420
+ * Normalization rules:
421
+ * 1. Sort object keys recursively
422
+ * 2. Remove null and undefined values
423
+ * 3. Recursively normalize nested objects
424
+ * 4. Preserve arrays as-is (order matters)
425
+ *
426
+ * @param args - Arguments object to normalize
427
+ * @returns Normalized arguments object
428
+ */
429
+ export function normalizeArgs(args) {
430
+ // Handle null/undefined
431
+ if (args === null || args === undefined) {
432
+ return {};
433
+ }
434
+ // Sort keys and filter out null/undefined values
435
+ const sortedKeys = Object.keys(args).sort();
436
+ const normalized = sortedKeys.reduce((acc, key) => {
437
+ const value = args[key];
438
+ // Skip null and undefined values
439
+ if (value === null || value === undefined) {
440
+ return acc;
441
+ }
442
+ // Recursively normalize nested objects
443
+ if (typeof value === 'object' && !Array.isArray(value)) {
444
+ acc[key] = normalizeArgs(value);
445
+ }
446
+ else {
447
+ // Keep primitives and arrays as-is
448
+ acc[key] = value;
449
+ }
450
+ return acc;
451
+ }, {});
452
+ return normalized;
453
+ }
454
+ //# sourceMappingURL=cache-manager.js.map
@@ -0,0 +1,66 @@
1
+ import { z } from 'zod';
2
+ export declare const ConfidenceSemanticsSchema: z.ZodObject<{
3
+ score_kind: z.ZodEnum<["heuristic_reconstruction", "runtime_correlation", "naming_resolution", "report_assessment"]>;
4
+ score: z.ZodNullable<z.ZodNumber>;
5
+ band: z.ZodEnum<["none", "low", "medium", "high"]>;
6
+ calibrated: z.ZodBoolean;
7
+ meaning: z.ZodString;
8
+ compare_within: z.ZodString;
9
+ caution: z.ZodString;
10
+ acceptance_rule: z.ZodOptional<z.ZodNullable<z.ZodString>>;
11
+ drivers: z.ZodArray<z.ZodString, "many">;
12
+ }, "strip", z.ZodTypeAny, {
13
+ score: number | null;
14
+ score_kind: "heuristic_reconstruction" | "runtime_correlation" | "naming_resolution" | "report_assessment";
15
+ band: "high" | "none" | "low" | "medium";
16
+ calibrated: boolean;
17
+ meaning: string;
18
+ compare_within: string;
19
+ caution: string;
20
+ drivers: string[];
21
+ acceptance_rule?: string | null | undefined;
22
+ }, {
23
+ score: number | null;
24
+ score_kind: "heuristic_reconstruction" | "runtime_correlation" | "naming_resolution" | "report_assessment";
25
+ band: "high" | "none" | "low" | "medium";
26
+ calibrated: boolean;
27
+ meaning: string;
28
+ compare_within: string;
29
+ caution: string;
30
+ drivers: string[];
31
+ acceptance_rule?: string | null | undefined;
32
+ }>;
33
+ export type ConfidenceSemantics = z.infer<typeof ConfidenceSemanticsSchema>;
34
+ export declare function confidenceBand(score: number | null | undefined): z.infer<typeof ConfidenceSemanticsSchema>['band'];
35
+ export declare function buildReconstructionConfidenceSemantics(input: {
36
+ score: number;
37
+ breakdown: {
38
+ decompile: number;
39
+ cfg: number;
40
+ assembly: number;
41
+ context: number;
42
+ };
43
+ runtimeConfidence?: number | null;
44
+ }): ConfidenceSemantics;
45
+ export declare function buildRuntimeConfidenceSemantics(input: {
46
+ score: number | null | undefined;
47
+ matchedApis?: string[];
48
+ matchedStages?: string[];
49
+ matchedMemoryRegions?: string[];
50
+ executed?: boolean;
51
+ evidenceSources?: string[];
52
+ }): ConfidenceSemantics | null;
53
+ export declare function buildNamingConfidenceSemantics(input: {
54
+ resolutionSource: 'rule' | 'llm' | 'hybrid' | 'unresolved';
55
+ renameConfidence?: number | null;
56
+ llmConfidence?: number | null;
57
+ ruleBasedName?: string | null;
58
+ validatedName?: string | null;
59
+ }): ConfidenceSemantics;
60
+ export declare function buildReportConfidenceSemantics(input: {
61
+ score: number;
62
+ evidenceScope: 'all' | 'latest' | 'session';
63
+ runtimeLayers?: string[];
64
+ executedTracePresent?: boolean;
65
+ }): ConfidenceSemantics;
66
+ //# sourceMappingURL=confidence-semantics.d.ts.map
@@ -0,0 +1,122 @@
1
+ import { z } from 'zod';
2
+ export const ConfidenceSemanticsSchema = z.object({
3
+ score_kind: z.enum([
4
+ 'heuristic_reconstruction',
5
+ 'runtime_correlation',
6
+ 'naming_resolution',
7
+ 'report_assessment',
8
+ ]),
9
+ score: z.number().min(0).max(1).nullable(),
10
+ band: z.enum(['none', 'low', 'medium', 'high']),
11
+ calibrated: z.boolean(),
12
+ meaning: z.string(),
13
+ compare_within: z.string(),
14
+ caution: z.string(),
15
+ acceptance_rule: z.string().nullable().optional(),
16
+ drivers: z.array(z.string()),
17
+ });
18
+ function clamp(value, min, max) {
19
+ return Math.max(min, Math.min(max, value));
20
+ }
21
+ export function confidenceBand(score) {
22
+ if (typeof score !== 'number' || Number.isNaN(score)) {
23
+ return 'none';
24
+ }
25
+ if (score >= 0.75) {
26
+ return 'high';
27
+ }
28
+ if (score >= 0.45) {
29
+ return 'medium';
30
+ }
31
+ return 'low';
32
+ }
33
+ export function buildReconstructionConfidenceSemantics(input) {
34
+ const drivers = [
35
+ input.breakdown.decompile > 0 ? `decompile=${input.breakdown.decompile.toFixed(2)}` : '',
36
+ input.breakdown.cfg > 0 ? `cfg=${input.breakdown.cfg.toFixed(2)}` : '',
37
+ input.breakdown.assembly > 0 ? `assembly=${input.breakdown.assembly.toFixed(2)}` : '',
38
+ input.breakdown.context > 0 ? `context=${input.breakdown.context.toFixed(2)}` : '',
39
+ typeof input.runtimeConfidence === 'number' && input.runtimeConfidence > 0
40
+ ? `runtime_correlation=${input.runtimeConfidence.toFixed(2)}`
41
+ : '',
42
+ ].filter((item) => item.length > 0);
43
+ return {
44
+ score_kind: 'heuristic_reconstruction',
45
+ score: clamp(input.score, 0, 1),
46
+ band: confidenceBand(input.score),
47
+ calibrated: false,
48
+ meaning: 'Heuristic evidence score for reconstruction quality. Higher values mean stronger decompile/CFG/assembly/context support, not probability of semantic correctness.',
49
+ compare_within: 'Compare across functions produced by the same tool version and evidence scope, not across unrelated tools or datasets.',
50
+ caution: 'Treat as ranking-oriented guidance. Low-level helper functions can still be correct at lower scores, and large complex functions can still contain wrong details at high scores.',
51
+ drivers,
52
+ };
53
+ }
54
+ export function buildRuntimeConfidenceSemantics(input) {
55
+ if (typeof input.score !== 'number' || Number.isNaN(input.score)) {
56
+ return null;
57
+ }
58
+ const drivers = [
59
+ (input.matchedApis || []).length > 0 ? `matched_apis=${(input.matchedApis || []).length}` : '',
60
+ (input.matchedStages || []).length > 0 ? `matched_stages=${(input.matchedStages || []).length}` : '',
61
+ (input.matchedMemoryRegions || []).length > 0
62
+ ? `matched_regions=${(input.matchedMemoryRegions || []).length}`
63
+ : '',
64
+ input.executed ? 'executed_trace=yes' : 'executed_trace=no',
65
+ (input.evidenceSources || []).length > 0
66
+ ? `sources=${(input.evidenceSources || []).slice(0, 3).join(',')}`
67
+ : '',
68
+ ].filter((item) => item.length > 0);
69
+ return {
70
+ score_kind: 'runtime_correlation',
71
+ score: clamp(input.score, 0, 1),
72
+ band: confidenceBand(input.score),
73
+ calibrated: false,
74
+ meaning: 'Heuristic overlap score between this function and runtime evidence. Higher values mean more API/stage/region corroboration, not proof that the entire function executed.',
75
+ compare_within: 'Compare across functions under the same evidence_scope and selected runtime artifacts.',
76
+ caution: 'String-heavy memory snapshots and shared helper routines can inflate overlap without proving exact control-flow execution.',
77
+ drivers,
78
+ };
79
+ }
80
+ export function buildNamingConfidenceSemantics(input) {
81
+ const baseScore = input.resolutionSource === 'llm'
82
+ ? input.llmConfidence ?? null
83
+ : input.renameConfidence ?? input.llmConfidence ?? null;
84
+ const drivers = [
85
+ input.ruleBasedName ? `rule_name=${input.ruleBasedName}` : '',
86
+ input.validatedName ? `validated_name=${input.validatedName}` : '',
87
+ typeof input.renameConfidence === 'number' ? `rule_score=${input.renameConfidence.toFixed(2)}` : '',
88
+ typeof input.llmConfidence === 'number' ? `llm_score=${input.llmConfidence.toFixed(2)}` : '',
89
+ `resolution_source=${input.resolutionSource}`,
90
+ ].filter((item) => item.length > 0);
91
+ return {
92
+ score_kind: 'naming_resolution',
93
+ score: typeof baseScore === 'number' ? clamp(baseScore, 0, 1) : null,
94
+ band: confidenceBand(baseScore),
95
+ calibrated: false,
96
+ meaning: 'Semantic naming confidence for the chosen label. It ranks naming support strength, not certainty that the recovered name matches the original source identifier.',
97
+ compare_within: 'Compare across names generated by the same naming pipeline version. Rule-based and LLM-suggested scores are still heuristic.',
98
+ caution: 'A validated name can still be approximate. Original developer naming cannot be reconstructed from this score alone.',
99
+ acceptance_rule: 'Rule-based names currently take priority. Pure LLM suggestions are promoted to validated_name only when llm_confidence >= 0.62.',
100
+ drivers,
101
+ };
102
+ }
103
+ export function buildReportConfidenceSemantics(input) {
104
+ const drivers = [
105
+ `evidence_scope=${input.evidenceScope}`,
106
+ (input.runtimeLayers || []).length > 0
107
+ ? `runtime_layers=${(input.runtimeLayers || []).join('>')}`
108
+ : 'runtime_layers=static_only',
109
+ input.executedTracePresent ? 'executed_trace=yes' : 'executed_trace=no',
110
+ ];
111
+ return {
112
+ score_kind: 'report_assessment',
113
+ score: clamp(input.score, 0, 1),
114
+ band: confidenceBand(input.score),
115
+ calibrated: false,
116
+ meaning: 'Assessment confidence for the generated report or triage summary. It indicates evidence strength and corroboration depth, not a calibrated threat probability.',
117
+ compare_within: 'Compare within the same report mode, tool version, and evidence scope.',
118
+ caution: 'Threat or intent judgments remain evidence-sensitive and can shift when scope changes from all to latest/session or when stronger runtime evidence is added.',
119
+ drivers,
120
+ };
121
+ }
122
+ //# sourceMappingURL=confidence-semantics.js.map