rea-agents 5.0.0 → 6.0.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 (275) hide show
  1. package/README.md +157 -650
  2. package/bridge/mitmproxy/capture.py +210 -0
  3. package/bridge/native/rea_lldb_tracer.py +303 -0
  4. package/bridge/process/ProcessRunTokenReader.swift +263 -0
  5. package/bridge/process/ProcessRunTokenReaderMain.swift +35 -0
  6. package/bridge/pwndbg/core_context.py +101 -0
  7. package/bridge/pwndbg/launch.py +39 -0
  8. package/bridge/pwndbg/launch_impl.py +34 -0
  9. package/bridge/pwntools/decoder_runtime.py +59 -0
  10. package/bridge/pwntools/layout.py +39 -0
  11. package/bridge/pwntools/layout_impl.py +309 -0
  12. package/bridge/pwntools/recorded_crash.py +39 -0
  13. package/bridge/pwntools/recorded_crash_impl.py +143 -0
  14. package/dist/android/JadxProvider.js +1 -0
  15. package/dist/application/CapabilityInventory.js +21 -0
  16. package/dist/application/DirectAnalysis.js +97 -23
  17. package/dist/application/EvidenceBundleFiles.js +1 -1
  18. package/dist/application/ReconstructionObligationCandidates.js +5 -1
  19. package/dist/application/WebNetworkCapturePort.js +1 -0
  20. package/dist/application/WebNetworkCaptureService.js +132 -0
  21. package/dist/application/WindowsCapabilities.js +1 -1
  22. package/dist/application/binary/AnalysisSnapshotCache.js +49 -6
  23. package/dist/application/binary/BinarySession.js +38 -10
  24. package/dist/application/binary/BinarySessionOpen.js +16 -3
  25. package/dist/application/binary/BinarySessionRecords.js +20 -0
  26. package/dist/application/binaryDiagnostics/BinaryLayoutPort.js +1 -0
  27. package/dist/application/binaryDiagnostics/BinaryLayoutService.js +57 -0
  28. package/dist/application/binaryDiagnostics/RecordedCrashPort.js +1 -0
  29. package/dist/application/binaryDiagnostics/RecordedCrashService.js +60 -0
  30. package/dist/application/evm/EvmInterfacePort.js +1 -0
  31. package/dist/application/evm/EvmInterfaceService.js +62 -0
  32. package/dist/application/javascript/JavaScriptApplicationEvidence.js +1 -2
  33. package/dist/application/javascript/JavaScriptApplicationService.js +15 -2
  34. package/dist/application/javascript/JavaScriptArtifactAnalysis.js +42 -23
  35. package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +26 -2
  36. package/dist/application/javascript/JavaScriptArtifactPathResolution.js +74 -24
  37. package/dist/application/javascript/JavaScriptArtifactReconstruction.js +23 -10
  38. package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +7 -7
  39. package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +145 -70
  40. package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +14 -15
  41. package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +41 -1
  42. package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +7 -7
  43. package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +5 -9
  44. package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +3 -3
  45. package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +118 -12
  46. package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +3 -3
  47. package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +5 -5
  48. package/dist/application/{ProcessCli.js → process/ProcessCli.js} +10 -10
  49. package/dist/application/{ProcessEvidence.js → process/ProcessEvidence.js} +4 -4
  50. package/dist/artifacts/ArtifactProvider.js +30 -3
  51. package/dist/artifacts/ArtifactProviderMetadata.js +2 -1
  52. package/dist/artifacts/ZipArtifactReader.js +3 -0
  53. package/dist/artifacts/apple/DylibResolutionReader.js +259 -0
  54. package/dist/artifacts/apple/MachoLoadCommandReader.js +294 -0
  55. package/dist/{application → artifacts/extraction}/ArtifactExtraction.js +10 -10
  56. package/dist/{application → artifacts/inventory}/ArtifactGraphConstruction.js +3 -3
  57. package/dist/{application → artifacts/inventory}/ArtifactInventory.js +4 -4
  58. package/dist/{application/ArtifactInventory → artifacts/inventory}/classify.js +2 -2
  59. package/dist/{application/ArtifactInventory → artifacts/inventory}/reader.js +5 -5
  60. package/dist/{application/ArtifactInventory → artifacts/inventory}/scanCanonical.js +3 -3
  61. package/dist/{application/ArtifactInventory → artifacts/inventory}/scanReader.js +5 -5
  62. package/dist/artifacts/readStableArtifact.js +20 -4
  63. package/dist/browser/CdpCaptureEventHandlers.js +90 -2
  64. package/dist/browser/CdpCaptureEvents.js +9 -0
  65. package/dist/browser/PlaywrightElectronActiveProvider.js +12 -3
  66. package/dist/browser/history/CaptureFailures.js +101 -0
  67. package/dist/browser/history/CaptureFormatError.js +10 -0
  68. package/dist/browser/history/CaptureRedaction.js +65 -0
  69. package/dist/browser/history/CaptureRelease.js +12 -0
  70. package/dist/browser/history/HarCapture.js +165 -0
  71. package/dist/browser/history/HarCaptureAdapter.js +20 -0
  72. package/dist/browser/history/HarCaptureProcess.js +57 -0
  73. package/dist/browser/history/HarJson.js +91 -0
  74. package/dist/browser/history/HarSchema.js +72 -0
  75. package/dist/browser/history/HistoricalCaptureDecoder.js +186 -0
  76. package/dist/browser/history/HistoricalCaptureFormatAdapter.js +1 -0
  77. package/dist/browser/history/MitmproxyCaptureAdapter.js +42 -0
  78. package/dist/cli/artifactCommands.js +26 -1
  79. package/dist/cli/binaryDiagnosticsCommands.js +39 -0
  80. package/dist/cli/coreAnalysisCommands.js +2 -2
  81. package/dist/cli/coreBinaryCommands.js +8 -8
  82. package/dist/cli/electronCommands.js +16 -9
  83. package/dist/cli/evmCommands.js +24 -0
  84. package/dist/cli/firmwareCommands.js +6 -3
  85. package/dist/cli/javascriptApplicationAnalysis.js +16 -3
  86. package/dist/cli/jsonOutput.js +133 -0
  87. package/dist/cli/nativeCallCommands.js +35 -0
  88. package/dist/cli/processCommands.js +1 -1
  89. package/dist/cli/streamedJsonOutput.js +56 -0
  90. package/dist/cli/utilityCommands.js +2 -0
  91. package/dist/cli/webNetworkCaptureCommands.js +40 -0
  92. package/dist/cli.js +9 -3
  93. package/dist/cliBrowserScenarioCommands.js +2 -2
  94. package/dist/cliCommandNames.js +6 -0
  95. package/dist/cliJsonInput.js +30 -1
  96. package/dist/cliOutput.js +21 -6
  97. package/dist/composition/binaryDiagnostics.js +8 -0
  98. package/dist/composition/evm.js +4 -0
  99. package/dist/composition/webNetworkCaptures.js +6 -0
  100. package/dist/contracts/artifactToolContracts.js +6 -0
  101. package/dist/contracts/browserCaptureToolInputSchema.js +43 -0
  102. package/dist/contracts/browserToolContracts.js +4 -3
  103. package/dist/contracts/errorSchemas.js +8 -1
  104. package/dist/contracts/evm/evmToolContracts.js +20 -0
  105. package/dist/contracts/investigationExamples.js +2 -2
  106. package/dist/contracts/managed/managedToolContracts.js +7 -3
  107. package/dist/contracts/native/binaryDiagnosticsToolContracts.js +42 -0
  108. package/dist/contracts/native/nativeToolContracts.js +17 -1
  109. package/dist/contracts/officialToolContracts.js +12 -9
  110. package/dist/contracts/process/processCaptureExample.js +2 -0
  111. package/dist/contracts/sessionLifecycleInputs.js +22 -5
  112. package/dist/contracts/sessionStatusContract.js +10 -2
  113. package/dist/contracts/sessionToolContracts.js +8 -1
  114. package/dist/contracts/sessionToolSchemas.js +10 -3
  115. package/dist/contracts/toolContractExamples.js +1 -1
  116. package/dist/contracts/toolContracts.js +6 -0
  117. package/dist/contracts/toolEffects.js +30 -0
  118. package/dist/contracts/toolOutputSchemaGroups.js +5 -1
  119. package/dist/contracts/toolOutputSchemaPrimitives.js +1 -1
  120. package/dist/contracts/webNetworkCaptureToolContracts.js +24 -0
  121. package/dist/domain/analysisErrorBase.js +15 -0
  122. package/dist/domain/analysisErrorCore.js +59 -5
  123. package/dist/domain/analysisErrorPresentation.js +29 -1
  124. package/dist/domain/analysisErrorProjection.js +52 -2
  125. package/dist/domain/analysisSnapshot.js +166 -2
  126. package/dist/domain/apple/dyldPaths.js +81 -0
  127. package/dist/domain/apple/dylibResolution.js +367 -0
  128. package/dist/domain/apple/dylibResolutionFindings.js +75 -0
  129. package/dist/domain/artifactPathSyntax.js +1 -1
  130. package/dist/domain/browserObservation.js +1 -1
  131. package/dist/domain/browserObservationSchemas.js +13 -0
  132. package/dist/domain/browserScenarioValues.js +9 -2
  133. package/dist/domain/callPathSchemas.js +1 -1
  134. package/dist/domain/canonicalDigest.js +13 -1
  135. package/dist/domain/changedBehavior.js +3 -3
  136. package/dist/domain/comparisonStatus.js +2 -30
  137. package/dist/domain/conformanceTrustGate.js +0 -16
  138. package/dist/domain/evidence.js +17 -5
  139. package/dist/domain/evm/evmInterface.js +63 -0
  140. package/dist/domain/explicitSensitiveFailure.js +92 -0
  141. package/dist/domain/explicitSensitiveValues.js +10 -0
  142. package/dist/domain/firmware/firmwareAnalysis.js +8 -1
  143. package/dist/domain/javascript/electronActiveObservation.js +9 -4
  144. package/dist/domain/javascript/htmlArtifactReferences.js +40 -0
  145. package/dist/domain/javascript/javascriptExportShapeComparison.js +21 -5
  146. package/dist/domain/javascript/javascriptExportShapeVariants.js +0 -10
  147. package/dist/domain/javascript/javascriptSemanticGraph.js +21 -5
  148. package/dist/domain/jsonValue.js +4 -0
  149. package/dist/domain/localPath.js +2 -0
  150. package/dist/domain/native/binaryLayout.js +357 -0
  151. package/dist/domain/native/nativeCallObservation.js +164 -0
  152. package/dist/domain/native/objcSwiftMetadata.js +0 -39
  153. package/dist/domain/native/recordedCrash.js +266 -0
  154. package/dist/domain/native/recordedCrashNoteCoverage.js +73 -0
  155. package/dist/domain/{processCapture.js → process/processCapture.js} +139 -2
  156. package/dist/domain/{processCaptureExample.js → process/processCaptureExample.js} +5 -0
  157. package/dist/domain/process/processCaptureParsing.js +54 -0
  158. package/dist/domain/{processCaptureValidation.js → process/processCaptureValidation.js} +18 -2
  159. package/dist/domain/{processComparison.js → process/processComparison.js} +1 -1
  160. package/dist/domain/{processObservation.js → process/processObservation.js} +1 -1
  161. package/dist/domain/{processTraceSpecification.js → process/processTraceSpecification.js} +1 -1
  162. package/dist/domain/providerSelectionError.js +4 -2
  163. package/dist/domain/reconstructionVerification.js +3 -3
  164. package/dist/domain/reconstructionVerificationSchemas.js +1 -1
  165. package/dist/domain/residualUnknown.js +3 -2
  166. package/dist/domain/staticRuntimeCorrelation.js +3 -3
  167. package/dist/domain/webCaptureDiff.js +1 -0
  168. package/dist/domain/webNetworkCapture.js +118 -0
  169. package/dist/domain/webNetworkCaptureCoordinates.js +58 -0
  170. package/dist/dotnet/ManagedExceptionRegionValidation.js +41 -0
  171. package/dist/dotnet/ManagedMemberInspector.js +4 -2
  172. package/dist/dotnet/ManagedMemberInspectorCore.js +38 -32
  173. package/dist/dotnet/ManagedMemberInstructionDecoder.js +23 -7
  174. package/dist/dotnet/ManagedMemberRows.js +14 -3
  175. package/dist/dotnet/ManagedMetadataHeaps.js +20 -2
  176. package/dist/dotnet/ManagedMetadataInventory.js +38 -28
  177. package/dist/dotnet/ManagedMetadataInventoryRows.js +24 -10
  178. package/dist/dotnet/ManagedMethodBodyReader.js +7 -1
  179. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +15 -3
  180. package/dist/dotnet/ManagedNativeBoundaryInspector.js +3 -1
  181. package/dist/dotnet/ManagedPeReader.js +11 -0
  182. package/dist/evm/EvmBytecodeCarrier.js +21 -0
  183. package/dist/evm/EvmWorkerLimits.js +40 -0
  184. package/dist/evm/EvmoleFailures.js +126 -0
  185. package/dist/evm/EvmoleInterfaceAdapter.js +53 -0
  186. package/dist/evm/EvmoleInterfaceProvider.js +273 -0
  187. package/dist/evm/EvmoleInterfaceWorker.js +87 -0
  188. package/dist/evm/EvmoleRelease.js +16 -0
  189. package/dist/firmware/FirmwareCommand.js +1 -0
  190. package/dist/generatedPackageMetadata.js +2 -2
  191. package/dist/ghidra/GhidraLauncher.js +1 -0
  192. package/dist/ghidra/GhidraProvider.js +2 -2
  193. package/dist/ghidra/GhidraProviderCapabilities.js +1 -1
  194. package/dist/hopper/BridgeLauncher.js +2 -0
  195. package/dist/hopper/LinuxPrivateDisplayProbe.js +4 -2
  196. package/dist/javascript/recovery/WakaruCommand.js +3 -0
  197. package/dist/javascript/sourceMaps/SourceMapCommand.js +1 -0
  198. package/dist/native/CommandRunner.js +2 -1
  199. package/dist/native/LldbCallTracer.js +278 -0
  200. package/dist/native/NativeCallObservation.js +135 -0
  201. package/dist/native/NativeMacOSProvider.js +19 -3
  202. package/dist/native/NativeMacOSProviderMetadata.js +8 -3
  203. package/dist/native/pwndbg/PwndbgCoreContext.js +160 -0
  204. package/dist/native/pwntools/PwntoolsDecoder.js +203 -0
  205. package/dist/native/pwntools/PwntoolsFailures.js +180 -0
  206. package/dist/native/pwntools/PwntoolsLayoutProvider.js +36 -0
  207. package/dist/native/pwntools/PwntoolsRecordedCrashProvider.js +75 -0
  208. package/dist/native/pwntools/PwntoolsRelease.js +19 -0
  209. package/dist/native/pwntools/PwntoolsResourceLimits.js +76 -0
  210. package/dist/native/pwntools/RecordedCrashSourceBindings.js +46 -0
  211. package/dist/native/pwntools/RecordedCrashStructureBindings.js +101 -0
  212. package/dist/process/DarwinProcessRunTokenReader.js +294 -0
  213. package/dist/process/OwnedCommand.js +113 -0
  214. package/dist/process/ProcessOwnership.js +263 -33
  215. package/dist/process/ProcessOwnershipObservation.js +161 -24
  216. package/dist/process/ProviderProcess.js +30 -3
  217. package/dist/{application → process/capture}/ProcessCaptureCapability.js +15 -0
  218. package/dist/{application → process/capture}/ProcessCaptureError.js +17 -1
  219. package/dist/process/capture/ProcessCaptureLifecycle.js +615 -0
  220. package/dist/{application → process/capture}/ProcessHarness.js +195 -29
  221. package/dist/{application → process/capture}/ProcessSampling.js +2 -2
  222. package/dist/server/createServer.js +22 -0
  223. package/dist/server/promptCompletion.js +10 -3
  224. package/dist/server/registerBinaryDiagnosticsTools.js +17 -0
  225. package/dist/server/registerEvidenceTools.js +1 -1
  226. package/dist/server/registerEvmTools.js +17 -0
  227. package/dist/server/registerProcessComparisonTool.js +1 -1
  228. package/dist/server/registerRecordedCrashTools.js +17 -0
  229. package/dist/server/registerSessionTools.js +2 -2
  230. package/dist/server/registerWebNetworkCaptureTool.js +28 -0
  231. package/dist/server/sessionAvailabilityPolicy.js +3 -0
  232. package/dist/server/sessionToolPolicies.js +1 -1
  233. package/dist/server/toolResult.js +1 -1
  234. package/native/windows/build/manifest.json +2 -2
  235. package/native/windows/build/rea-windows-x64.node +0 -0
  236. package/package.json +37 -9
  237. package/scripts/rea.mjs +11 -3
  238. package/skills/reverse-engineer-anything/SKILL.md +23 -3
  239. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +29 -0
  240. package/third_party/README.md +60 -0
  241. package/third_party/evmole/LICENSE +21 -0
  242. package/third_party/evmole/README.md +22 -0
  243. package/third_party/pwndbg/LICENSE.md +21 -0
  244. package/third_party/pwndbg/README.md +23 -0
  245. package/third_party/pwntools/README.md +40 -0
  246. package/dist/application/AuthorizedArtifactInventory.js +0 -7
  247. package/dist/application/ProcessCaptureLifecycle.js +0 -299
  248. package/dist/application/StoreFileLock.js +0 -124
  249. package/dist/contracts/processCaptureExample.js +0 -2
  250. package/dist/domain/bytecodeProvider.js +0 -178
  251. package/dist/domain/customProtocolCapture.js +0 -137
  252. package/dist/domain/eventProcessTree.js +0 -225
  253. package/dist/domain/mobileApplicationInvestigation.js +0 -159
  254. package/dist/domain/packageAnalysis.js +0 -123
  255. package/dist/domain/peInspection.js +0 -197
  256. package/dist/domain/processCaptureParsing.js +0 -21
  257. package/dist/domain/protocolCapture.js +0 -217
  258. package/dist/domain/runtimeIdentification.js +0 -212
  259. package/dist/generatedMcpToolCatalog.js +0 -37
  260. /package/dist/application/{ArtifactExtractionDestination.js → artifacts/ArtifactExtractionDestination.js} +0 -0
  261. /package/dist/{application/ArtifactInventory → artifacts/inventory}/policy.js +0 -0
  262. /package/dist/{application/ArtifactInventory → artifacts/inventory}/types.js +0 -0
  263. /package/dist/domain/{processEvidenceProvider.js → process/processEvidenceProvider.js} +0 -0
  264. /package/dist/domain/{processScenario.js → process/processScenario.js} +0 -0
  265. /package/dist/domain/{processTraceComparison.js → process/processTraceComparison.js} +0 -0
  266. /package/dist/domain/{processTraceDimensionProjection.js → process/processTraceDimensionProjection.js} +0 -0
  267. /package/dist/domain/{processTraceEvaluation.js → process/processTraceEvaluation.js} +0 -0
  268. /package/dist/{application → process/capture}/FilesystemSnapshot.js +0 -0
  269. /package/dist/{application → process/capture}/ProcessCaptureEnvironment.js +0 -0
  270. /package/dist/{application → process/capture}/ProcessCaptureJournal.js +0 -0
  271. /package/dist/{application → process/capture}/ProcessFilesystemEffects.js +0 -0
  272. /package/dist/{application → process/capture}/ProcessNormalization.js +0 -0
  273. /package/dist/{application → process/capture}/ProcessScenarioRuntimeValidation.js +0 -0
  274. /package/dist/{application → process/capture}/ProcessTimer.js +0 -0
  275. /package/dist/{application → process/capture}/TerminalRenderer.js +0 -0
@@ -27,7 +27,31 @@ const uniqueIssues = (issues) => [
27
27
  ...new Map(issues.map((issue) => [JSON.stringify(issue), issue])).values(),
28
28
  ];
29
29
  const heapExtent = (layout) => Math.max(layout.strings.size, layout.blob.size);
30
- const readReferences = (bytes, layout, issues) => readRows(layout.table(35), (row) => safeRead(() => readAssemblyReference(bytes, layout, row, heapExtent(layout)), issues));
30
+ const validateIdentityTableCounts = (layout, issues) => {
31
+ const moduleRows = layout.table(0)?.rowCount ?? 0;
32
+ if (moduleRows !== 1)
33
+ issues.push({
34
+ code: "invalid-row",
35
+ scope: "metadata.Module",
36
+ offset: layout.table(0)?.offset ?? null,
37
+ detail: `Module table must contain exactly one row; found ${String(moduleRows)}`,
38
+ });
39
+ const assemblyRows = layout.table(32)?.rowCount ?? 0;
40
+ if (assemblyRows > 1)
41
+ issues.push({
42
+ code: "invalid-row",
43
+ scope: "metadata.Assembly",
44
+ offset: layout.table(32)?.offset ?? null,
45
+ detail: `Assembly table can contain at most one row; found ${String(assemblyRows)}`,
46
+ });
47
+ };
48
+ const readReferences = (bytes, layout, issues) => {
49
+ const references = readRows(layout.table(35), (row) => safeRead(() => readAssemblyReference(bytes, layout, row, heapExtent(layout)), issues));
50
+ return {
51
+ references,
52
+ referenceNames: [...new Set(references.map(({ name }) => name))].sort(),
53
+ };
54
+ };
31
55
  const readResources = ({ bytes, layout, resourceDirectory, issues, }) => readRows(layout.table(40), (row) => safeRead(() => readResource({
32
56
  bytes,
33
57
  layout,
@@ -35,53 +59,39 @@ const readResources = ({ bytes, layout, resourceDirectory, issues, }) => readRow
35
59
  directory: resourceDirectory,
36
60
  issues,
37
61
  }), issues));
38
- const readAttributes = (bytes, layout, issues) => readRows(layout.table(12), (row) => safeRead(() => readCustomAttribute(bytes, layout, row, heapExtent(layout)), issues));
39
- const collectReferenceNames = (bytes, layout, issues) => {
40
- const names = [];
41
- const referenceTable = layout.table(35);
42
- for (let row = 1; row <= (referenceTable?.rowCount ?? 0); row += 1) {
43
- const reference = safeRead(() => readAssemblyReference(bytes, layout, row, heapExtent(layout)), issues);
44
- if (reference !== undefined)
45
- names.push(reference.name);
46
- }
47
- return names;
48
- };
49
- const collectTargetFrameworks = (bytes, layout, issues) => {
50
- const targetFrameworks = [];
51
- const attributeTable = layout.table(12);
52
- for (let row = 1; row <= (attributeTable?.rowCount ?? 0); row += 1) {
53
- const attribute = safeRead(() => readCustomAttribute(bytes, layout, row, heapExtent(layout)), issues);
54
- if (attribute?.parent_token === metadataToken(32, 1) &&
62
+ const readAttributes = (bytes, layout, issues) => {
63
+ const attributes = readRows(layout.table(12), (row) => safeRead(() => readCustomAttribute(bytes, layout, row, heapExtent(layout)), issues));
64
+ const targetFrameworks = new Set();
65
+ for (const attribute of attributes) {
66
+ if (attribute.parent_token === metadataToken(32, 1) &&
55
67
  attribute.type_name ===
56
68
  "System.Runtime.Versioning.TargetFrameworkAttribute" &&
57
- attribute.decoded_fixed_string !== null &&
58
- !targetFrameworks.includes(attribute.decoded_fixed_string))
59
- targetFrameworks.push(attribute.decoded_fixed_string);
69
+ attribute.decoded_fixed_string !== null)
70
+ targetFrameworks.add(attribute.decoded_fixed_string);
60
71
  }
61
- return targetFrameworks;
72
+ return { attributes, targetFrameworks: [...targetFrameworks].sort() };
62
73
  };
63
74
  /** Inventory identity tables without CLR reflection or execution. */
64
75
  export const readManagedMetadataInventory = (bytes, layout, resourceDirectory) => {
65
76
  const issues = [];
77
+ validateIdentityTableCounts(layout, issues);
66
78
  const module = safeRead(() => readModule(bytes, layout, heapExtent(layout)), issues) ??
67
79
  null;
68
80
  const assembly = safeRead(() => readAssembly(bytes, layout, heapExtent(layout)), issues) ??
69
81
  null;
70
- const references = readReferences(bytes, layout, issues);
82
+ const { references, referenceNames } = readReferences(bytes, layout, issues);
71
83
  const resources = readResources({
72
84
  bytes,
73
85
  layout,
74
86
  resourceDirectory,
75
87
  issues,
76
88
  });
77
- const attributes = readAttributes(bytes, layout, issues);
78
- const referenceNames = collectReferenceNames(bytes, layout, issues);
79
- const targetFrameworks = collectTargetFrameworks(bytes, layout, issues);
89
+ const { attributes, targetFrameworks } = readAttributes(bytes, layout, issues);
80
90
  return {
81
91
  module,
82
92
  assembly,
83
- targetFrameworks: [...targetFrameworks].sort(),
84
- referenceNames: [...new Set(referenceNames)].sort(),
93
+ targetFrameworks,
94
+ referenceNames,
85
95
  references,
86
96
  resources,
87
97
  attributes,
@@ -1,5 +1,5 @@
1
1
  import { metadataRowOffset, } from "./ManagedMetadataLayout.js";
2
- import { metadataRowCursor, metadataCodedToken, metadataToken, readMetadataBlob, readMetadataGuid, readMetadataString, sha256Bytes, strongNameToken, } from "./ManagedMetadataHeaps.js";
2
+ import { metadataRowCursor, metadataCodedToken, metadataCodedTokenInvalidReason, metadataToken, readMetadataBlob, readMetadataGuid, readMetadataString, sha256Bytes, strongNameToken, } from "./ManagedMetadataHeaps.js";
3
3
  import { managedFailure } from "./ManagedReaderFailure.js";
4
4
  const publicKeyIdentity = (bytes, kind) => ({
5
5
  kind: bytes.length === 0 ? "none" : kind,
@@ -212,23 +212,28 @@ const decodeFixedString = (blob) => {
212
212
  export const readCustomAttribute = (bytes, layout, row, heapExtent) => {
213
213
  const cursor = metadataRowCursor(bytes, layout, 12, row);
214
214
  const parentRaw = cursor.readIndex(layout.codedIndexSize("HasCustomAttribute"));
215
+ const typeOffset = cursor.offset;
215
216
  const typeRaw = cursor.readIndex(layout.codedIndexSize("CustomAttributeType"));
216
217
  const value = readMetadataBlob(bytes, layout, cursor.readIndex(layout.blobIndexSize), heapExtent);
217
218
  const parent = metadataCodedToken(parentRaw, 5, [
218
219
  6, 4, 1, 2, 8, 9, 10, 0, 14, 23, 20, 17, 26, 27, 32, 35, 38, 39, 40, 42,
219
220
  44, 43,
220
- ]);
221
+ ], layout.rowCounts);
222
+ const parentReason = metadataCodedTokenInvalidReason(parentRaw, 5, [
223
+ 6, 4, 1, 2, 8, 9, 10, 0, 14, 23, 20, 17, 26, 27, 32, 35, 38, 39, 40, 42,
224
+ 44, 43,
225
+ ], layout.rowCounts);
221
226
  if (parent === null)
222
- throw managedFailure("invalid-row", "metadata.CustomAttribute", "CustomAttribute parent coded index is invalid", cursor.start);
227
+ throw managedFailure("invalid-row", `metadata.CustomAttribute:${metadataToken(12, row)}`, `CustomAttribute parent coded index 0x${parentRaw.toString(16)} is invalid${parentReason === null ? " because the required parent is null" : `: ${parentReason}`}`, cursor.start);
228
+ const typeReason = metadataCodedTokenInvalidReason(typeRaw, 3, [undefined, undefined, 6, 10], layout.rowCounts);
229
+ if (typeReason !== null || typeRaw === 0)
230
+ throw managedFailure("invalid-row", `metadata.CustomAttribute:${metadataToken(12, row)}`, typeReason === null
231
+ ? "CustomAttribute constructor coded index 0x0 is null, but Type must reference a MethodDef or MemberRef row"
232
+ : `CustomAttribute constructor coded index 0x${typeRaw.toString(16)} is invalid: ${typeReason}`, typeOffset);
223
233
  const typeName = attributeTypeName(bytes, layout, typeRaw, heapExtent);
224
234
  return {
225
235
  parent_token: parent,
226
- constructor_token: metadataCodedToken(typeRaw, 3, [
227
- undefined,
228
- undefined,
229
- 6,
230
- 10,
231
- ]),
236
+ constructor_token: metadataCodedToken(typeRaw, 3, [undefined, undefined, 6, 10], layout.rowCounts),
232
237
  type_name: typeName,
233
238
  value_length: value.length,
234
239
  value_sha256: sha256Bytes(value),
@@ -244,8 +249,17 @@ export const readResource = ({ bytes, layout, row, directory, issues, }) => {
244
249
  const declaredOffset = cursor.readUInt32();
245
250
  const flags = cursor.readUInt32();
246
251
  const name = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), Math.max(layout.strings.size, layout.blob.size));
252
+ const implementationOffset = cursor.offset;
247
253
  const implementationRaw = cursor.readIndex(layout.codedIndexSize("Implementation"));
248
- const implementationToken = metadataCodedToken(implementationRaw, 2, [38, 35, 39]);
254
+ const implementationToken = metadataCodedToken(implementationRaw, 2, [38, 35, 39], layout.rowCounts);
255
+ const implementationReason = metadataCodedTokenInvalidReason(implementationRaw, 2, [38, 35, 39], layout.rowCounts);
256
+ if (implementationReason !== null)
257
+ issues.push({
258
+ code: "invalid-row",
259
+ scope: `metadata.ManifestResource:${metadataToken(40, row)}`,
260
+ offset: implementationOffset,
261
+ detail: `ManifestResource implementation coded index 0x${implementationRaw.toString(16)} is invalid: ${implementationReason}`,
262
+ });
249
263
  let dataLength = null;
250
264
  let dataSha256 = null;
251
265
  if (implementationRaw === 0) {
@@ -1,4 +1,5 @@
1
1
  import { decodeInstructions, parseExceptionRegions, } from "./ManagedMemberInstructionDecoder.js";
2
+ import { validateExceptionRegionRanges } from "./ManagedExceptionRegionValidation.js";
2
3
  import { sha256Bytes } from "./ManagedMetadataHeaps.js";
3
4
  const bodyStatus = (decodedIssue, truncatedInstructions, exceptionRegions) => {
4
5
  if (decodedIssue !== null || exceptionRegions?.status === "malformed")
@@ -38,6 +39,7 @@ const readMethodBodyHeader = (bytes, offset) => {
38
39
  localSig: bytes.readUInt32LE(offset + 8),
39
40
  };
40
41
  };
42
+ const readExceptionRegions = (bytes, sectionOffset, methodEnd, ilSize, instructionOffsets) => validateExceptionRegionRanges(parseExceptionRegions(bytes, sectionOffset, methodEnd), ilSize, instructionOffsets);
41
43
  /** Decode admitted managed CIL, retaining unavailable implementation metadata as partial. */
42
44
  export const methodBody = (bytes, pe, rva, implementation = {
43
45
  implFlags: 0,
@@ -50,7 +52,11 @@ export const methodBody = (bytes, pe, rva, implementation = {
50
52
  return emptyMethodBody(rva, "partial", "CIL decoding is unavailable for native, runtime, unmanaged, or P/Invoke implementations");
51
53
  try {
52
54
  const offset = pe.rvaToOffset(rva, 1, "method.body");
55
+ const methodExtent = pe.rvaAvailableBytes(rva, "method.body");
53
56
  const header = readMethodBodyHeader(bytes, offset);
57
+ if (header.size > methodExtent ||
58
+ header.ilSize > methodExtent - header.size)
59
+ throw new RangeError("Method body leaves file-backed PE section data");
54
60
  const ilOffset = offset + header.size;
55
61
  if (ilOffset > bytes.length - header.ilSize)
56
62
  throw new RangeError("Method IL bytes leave artifact");
@@ -76,7 +82,7 @@ export const methodBody = (bytes, pe, rva, implementation = {
76
82
  const methodEnd = ilOffset + header.ilSize;
77
83
  const sectionOffset = (methodEnd + 3) & ~3;
78
84
  const exceptionRegions = header.format === "fat" && (header.flags & 8) !== 0
79
- ? parseExceptionRegions(bytes, sectionOffset, bytes.length)
85
+ ? readExceptionRegions(bytes, sectionOffset, offset + methodExtent, header.ilSize, decoded.instructionStarts)
80
86
  : null;
81
87
  const status = bodyStatus(decoded.issue, decoded.truncated, exceptionRegions);
82
88
  return {
@@ -1,6 +1,6 @@
1
1
  import { managedNativeBoundaryInspectionSchema, } from "../domain/managed/managedArtifact.js";
2
2
  import {} from "./ManagedMetadataLayout.js";
3
- import { metadataRowCursor, metadataCodedToken, metadataToken, readMetadataString, } from "./ManagedMetadataHeaps.js";
3
+ import { metadataRowCursor, metadataCodedToken, metadataCodedTokenInvalidReason, metadataToken, readMetadataString, } from "./ManagedMetadataHeaps.js";
4
4
  import { managedTableRowCounts } from "./ManagedMetadataInventory.js";
5
5
  const flagsHex = (value) => `0x${value.toString(16).padStart(4, "0")}`;
6
6
  export const parseModuleRefs = (bytes, layout, heapExtent) => {
@@ -61,14 +61,26 @@ export const parseMethods = (bytes, layout, heapExtent) => {
61
61
  }
62
62
  return methods;
63
63
  };
64
- export const parseImplMaps = ({ bytes, layout, heapExtent, modules, members, }) => {
64
+ export const parseImplMaps = ({ bytes, layout, heapExtent, modules, members, issues, }) => {
65
65
  const moduleNames = new Map(modules.map((module) => [module.token, module]));
66
66
  const imports = [];
67
67
  const table = layout.table(28);
68
68
  for (let row = 1; row <= (table?.rowCount ?? 0); row += 1) {
69
69
  const cursor = metadataRowCursor(bytes, layout, 28, row);
70
70
  const mappingFlags = cursor.readUInt16();
71
- const memberToken = metadataCodedToken(cursor.readIndex(layout.codedIndexSize("MemberForwarded")), 1, [4, 6]);
71
+ const memberForwardedOffset = cursor.offset;
72
+ const memberForwardedRaw = cursor.readIndex(layout.codedIndexSize("MemberForwarded"));
73
+ const memberForwardedReason = metadataCodedTokenInvalidReason(memberForwardedRaw, 1, [4, 6], layout.rowCounts);
74
+ if (memberForwardedReason !== null || memberForwardedRaw === 0)
75
+ issues.push({
76
+ code: "invalid-row",
77
+ scope: `metadata.ImplMap:${metadataToken(28, row)}`,
78
+ offset: memberForwardedOffset,
79
+ detail: memberForwardedReason === null
80
+ ? "ImplMap MemberForwarded coded index 0x0 is null, but the column must reference a Field or MethodDef row"
81
+ : `ImplMap MemberForwarded coded index 0x${memberForwardedRaw.toString(16)} is invalid: ${memberForwardedReason}`,
82
+ });
83
+ const memberToken = metadataCodedToken(memberForwardedRaw, 1, [4, 6], layout.rowCounts);
72
84
  const importName = readMetadataString(bytes, layout, cursor.readIndex(layout.stringIndexSize), heapExtent);
73
85
  const importScopeRow = cursor.readIndex(layout.tableIndexSize(26));
74
86
  const importScopeToken = importScopeRow === 0 ? null : metadataToken(26, importScopeRow);
@@ -89,6 +89,7 @@ export const inspectManagedNativeBoundariesBytes = (bytes, target) => {
89
89
  });
90
90
  }
91
91
  const heapExtent = Math.max(layout.strings.size, layout.blob.size);
92
+ const issues = [...inventory.issues];
92
93
  const moduleRefs = parseModuleRefs(bytes, layout, heapExtent);
93
94
  const members = new Map([
94
95
  ...parseFields(bytes, layout, heapExtent),
@@ -100,6 +101,7 @@ export const inspectManagedNativeBoundariesBytes = (bytes, target) => {
100
101
  heapExtent,
101
102
  modules: moduleRefs,
102
103
  members,
104
+ issues,
103
105
  });
104
106
  const pinvokeTokens = new Set(imports
105
107
  .map(({ member_token }) => member_token)
@@ -115,6 +117,6 @@ export const inspectManagedNativeBoundariesBytes = (bytes, target) => {
115
117
  imports,
116
118
  implementations,
117
119
  native: cliNative(pe),
118
- issues: [],
120
+ issues,
119
121
  });
120
122
  };
@@ -186,5 +186,16 @@ export const readManagedPeLayout = (bytes) => {
186
186
  cliDirectoryPresent,
187
187
  cliIssue,
188
188
  rvaToOffset: (rva, size, scope) => mapRva({ bytes, sections, rva, size, scope }),
189
+ rvaAvailableBytes: (rva, scope) => {
190
+ mapRva({ bytes, sections, rva, size: 1, scope });
191
+ for (const section of sections) {
192
+ if (rva < section.virtualAddress)
193
+ continue;
194
+ const within = rva - section.virtualAddress;
195
+ if (within < section.rawSize)
196
+ return Math.min(section.rawSize - within, bytes.length - section.rawOffset - within);
197
+ }
198
+ throw managedFailure("invalid-directory", scope, `${scope} RVA is not covered by file-backed PE section data`);
199
+ },
189
200
  };
190
201
  };
@@ -0,0 +1,21 @@
1
+ /** Expected carrier encoding failure, independent of the analysis engine. */
2
+ export class EvmCarrierFailure extends Error {
3
+ }
4
+ /** Decode only the explicitly selected representation; source carrier bytes are retained separately. */
5
+ export const decodeEvmBytecodeCarrier = (bytes, encoding) => {
6
+ if (encoding === "raw")
7
+ return Uint8Array.from(bytes);
8
+ let text;
9
+ try {
10
+ text = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
11
+ }
12
+ catch (cause) {
13
+ throw new EvmCarrierFailure("Hex carrier must be valid UTF-8.", { cause });
14
+ }
15
+ const code = text
16
+ .replace(/^[\x09-\x0d\x20]+|[\x09-\x0d\x20]+$/g, "")
17
+ .replace(/^0x/i, "");
18
+ if (!/^(?:[a-fA-F0-9]{2})*$/.test(code))
19
+ throw new EvmCarrierFailure("Hex carrier requires complete hexadecimal byte pairs, an optional 0x prefix and outer ASCII whitespace; interior separators are invalid.");
20
+ return Uint8Array.from(Buffer.from(code, "hex"));
21
+ };
@@ -0,0 +1,40 @@
1
+ import { err, ok } from "../domain/result.js";
2
+ import { EVM_INTERFACE_LIMITS } from "./EvmoleRelease.js";
3
+ /** Read only the three selected Linux limits, retaining tighter soft/hard boundaries. */
4
+ export const selectEvmWorkerLimits = (raw) => {
5
+ if (typeof raw !== "string" || Buffer.byteLength(raw) > 64 * 1024)
6
+ return err("Linux resource limits must be text within the 64 KiB parsing budget.");
7
+ const selected = [];
8
+ for (const [name, units, maximum] of [
9
+ ["Max address space", "bytes", EVM_INTERFACE_LIMITS.addressSpaceBytes],
10
+ ["Max cpu time", "seconds", 30],
11
+ ["Max file size", "bytes", EVM_INTERFACE_LIMITS.outputBytes],
12
+ ]) {
13
+ const entries = raw
14
+ .split("\n")
15
+ .filter((line) => line.startsWith(name + " "));
16
+ if (entries.length !== 1)
17
+ return err(`Linux resource limits must report exactly one ${name} row.`);
18
+ const match = new RegExp(`^${name}\\s+(unlimited|[0-9]+)\\s+(unlimited|[0-9]+)\\s+${units}\\s*$`).exec(entries[0] ?? "");
19
+ if (match === null)
20
+ return err(`Malformed inherited Linux resource limit: ${name}.`);
21
+ let effective = BigInt(maximum);
22
+ const soft = match[1];
23
+ const hard = match[2];
24
+ if (soft === undefined || hard === undefined)
25
+ return err(`Missing ${name} values.`);
26
+ if (hard !== "unlimited" &&
27
+ (soft === "unlimited" || BigInt(soft) > BigInt(hard)))
28
+ return err(`Inherited ${name} soft limit exceeds its hard limit.`);
29
+ for (const value of [soft, hard])
30
+ if (value !== "unlimited" && BigInt(value) < effective)
31
+ effective = BigInt(value);
32
+ selected.push(Number(effective));
33
+ }
34
+ const [addressSpaceBytes, cpuSeconds, fileSizeBytes] = selected;
35
+ if (addressSpaceBytes === undefined ||
36
+ cpuSeconds === undefined ||
37
+ fileSizeBytes === undefined)
38
+ return err("Required Linux resource limits were not selected.");
39
+ return ok({ addressSpaceBytes, cpuSeconds, fileSizeBytes });
40
+ };
@@ -0,0 +1,126 @@
1
+ import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
2
+ import { AnalysisError, } from "../domain/analysisErrorBase.js";
3
+ import { AnalysisAccessDeniedError, AnalysisArtifactChangedError, AnalysisCapabilityUnavailableError, AnalysisCancelledError, AnalysisInputError, AnalysisOutputError, AnalysisResourceConstraintError, AnalysisTimeoutError, } from "../domain/analysisErrorCore.js";
4
+ import { ProviderAdapterError } from "../domain/providerAdapterError.js";
5
+ import { ProviderCleanupError } from "../domain/providerCleanupError.js";
6
+ import { OwnedCommandFailure } from "../process/OwnedCommand.js";
7
+ import { EVMOLE_PROVIDER_IDENTITY, EVM_INTERFACE_LIMITS, EVM_FILE_SIZE_FAILURE_EXIT, } from "./EvmoleRelease.js";
8
+ /** Keep carrier read, engine and owned lifecycle failures distinct. */
9
+ export const evmInterfaceFailure = (cause, phase, path, workerLimits, limiter = "/usr/bin/prlimit", fileFailure) => {
10
+ if (cause instanceof AnalysisError)
11
+ return cause;
12
+ if (cause instanceof OwnedCommandFailure) {
13
+ const outputOptions = cause.snapshot === null
14
+ ? undefined
15
+ : { capturedOutput: capturedEvmOutput(cause.snapshot) };
16
+ if (cause.cleanupFailure !== null)
17
+ return new ProviderCleanupError(EVMOLE_PROVIDER_IDENTITY.id, cause.resources, {
18
+ reason: cause.cleanupFailure,
19
+ ...(cause.snapshot === null
20
+ ? {}
21
+ : { captured_output: { ...capturedEvmOutput(cause.snapshot) } }),
22
+ previous_error: {
23
+ failure_kind: cause.reason,
24
+ message: cause.message,
25
+ exit_code: cause.snapshot?.exitCode ?? null,
26
+ signal: cause.snapshot?.signal ?? null,
27
+ stdout: cause.snapshot?.stdout.text ?? null,
28
+ stderr: cause.snapshot?.stderr.text ?? null,
29
+ },
30
+ }, { operation: "inspect_evm_interface", cause });
31
+ if (cause.reason === "cancelled")
32
+ return new AnalysisCancelledError("inspect_evm_interface", outputOptions);
33
+ if (cause.reason === "timeout")
34
+ return new AnalysisTimeoutError("inspect_evm_interface", EVM_INTERFACE_LIMITS.timeoutMs, outputOptions);
35
+ if (cause.reason === "output-limit")
36
+ return new AnalysisOutputError("inspect_evm_interface", cause.message, outputOptions);
37
+ if (cause.reason === "process" &&
38
+ (cause.snapshot?.signal === "SIGXCPU" ||
39
+ cause.snapshot?.signal === "SIGXFSZ" ||
40
+ (fileFailure?.verified === true &&
41
+ cause.snapshot?.exitCode === EVM_FILE_SIZE_FAILURE_EXIT &&
42
+ cause.snapshot.signal === null)))
43
+ return new AnalysisResourceConstraintError("inspect_evm_interface", cause.snapshot.signal === "SIGXCPU" ? "cpu" : "file-size", (cause.snapshot.signal === null
44
+ ? "Owned EVM worker reported EFBIG while writing its reply; the exact write failure cause is unknown."
45
+ : `Owned EVM command terminated with ${cause.snapshot.signal}; the exact signal cause is unknown.`) +
46
+ " Effective worker limits are unknown. Configured soft limits are retained separately.", workerLimits === undefined
47
+ ? null
48
+ : {
49
+ configured_soft_limits: {
50
+ address_space_bytes: workerLimits.addressSpaceBytes,
51
+ cpu_seconds: workerLimits.cpuSeconds,
52
+ file_size_bytes: workerLimits.fileSizeBytes,
53
+ },
54
+ effective_soft_limits: null,
55
+ }, outputOptions);
56
+ }
57
+ if (cause instanceof Error &&
58
+ "code" in cause &&
59
+ "syscall" in cause &&
60
+ typeof cause.syscall === "string" &&
61
+ cause.syscall.startsWith("spawn ")) {
62
+ const reason = `Configured util-linux prlimit could not launch (${String(cause.code)}): ${limiter}. Check its executable/interpreter and host execute access.`;
63
+ return new AnalysisCapabilityUnavailableError(EVMOLE_PROVIDER_IDENTITY.id, "inspect_evm_interface", reason, { cause, userMessage: reason });
64
+ }
65
+ if (cause instanceof ArtifactReaderFailure) {
66
+ if (cause.reason === "cancelled")
67
+ return new AnalysisCancelledError("inspect_evm_interface");
68
+ if (cause.reason === "integrity")
69
+ return new AnalysisArtifactChangedError("inspect_evm_interface", path, cause.message, { cause });
70
+ if (phase === "artifact-read" &&
71
+ ["limit", "path", "format"].includes(cause.reason))
72
+ return new AnalysisInputError("inspect_evm_interface", { cause }, [
73
+ {
74
+ path: ["path"],
75
+ reason: cause.reason === "limit" ? "out_of_range" : "invalid_format",
76
+ message: cause.message,
77
+ },
78
+ ]);
79
+ }
80
+ if (phase === "artifact-read" && cause instanceof Error && "code" in cause) {
81
+ if (cause.code === "EACCES" || cause.code === "EPERM")
82
+ return new AnalysisAccessDeniedError("inspect_evm_interface", path, cause.code, { cause });
83
+ if (cause.code === "ENOENT" || cause.code === "ENOTDIR")
84
+ return new AnalysisInputError("inspect_evm_interface", { cause }, [
85
+ {
86
+ path: ["path"],
87
+ reason: "invalid_value",
88
+ message: `Selected bytecode carrier could not be read (${String(cause.code)}): ${path}.`,
89
+ },
90
+ ]);
91
+ }
92
+ return new ProviderAdapterError(EVMOLE_PROVIDER_IDENTITY.id, "inspect_evm_interface", {
93
+ cause,
94
+ diagnostics: {
95
+ phase,
96
+ path,
97
+ ...(workerLimits === undefined
98
+ ? {}
99
+ : { configured_resource_limits: { ...workerLimits } }),
100
+ reason: cause instanceof Error ? cause.message : String(cause),
101
+ ...(fileFailure === undefined
102
+ ? {}
103
+ : { file_size_failure_marker: { ...fileFailure } }),
104
+ ...(cause instanceof OwnedCommandFailure
105
+ ? {
106
+ failure_kind: cause.reason,
107
+ exit_code: cause.snapshot?.exitCode ?? null,
108
+ signal: cause.snapshot?.signal ?? null,
109
+ stdout: cause.snapshot?.stdout.text ?? null,
110
+ stderr: cause.snapshot?.stderr.text ?? null,
111
+ ...(cause.snapshot === null
112
+ ? {}
113
+ : {
114
+ captured_output: { ...capturedEvmOutput(cause.snapshot) },
115
+ }),
116
+ }
117
+ : {}),
118
+ },
119
+ });
120
+ };
121
+ /** Preserve retained worker diagnostics with their observed truncation status. */
122
+ export const capturedEvmOutput = (snapshot) => ({
123
+ stdout: snapshot.stdout.text,
124
+ stderr: snapshot.stderr.text,
125
+ truncated: snapshot.diagnosticTruncated === true,
126
+ });
@@ -0,0 +1,53 @@
1
+ import { z } from "zod";
2
+ const offset = z.number().int().nonnegative();
3
+ const reportedMetadata = z.strictObject({
4
+ bytecodeOffset: offset,
5
+ cborLength: offset,
6
+ entries: z.array(z.strictObject({
7
+ key: z.string(),
8
+ value: z.discriminatedUnion("type", [
9
+ z.strictObject({ type: z.literal("string"), value: z.string() }),
10
+ z.strictObject({ type: z.literal("integer"), value: z.number() }),
11
+ z.strictObject({ type: z.literal("bytes"), value: z.string() }),
12
+ z.strictObject({ type: z.literal("bool"), value: z.boolean() }),
13
+ z.strictObject({ type: z.literal("undecoded"), value: z.string() }),
14
+ ]),
15
+ })),
16
+ });
17
+ /** Parse the exact producer representation before assigning portable field names. */
18
+ export const evmoleInterfaceReplySchema = z.strictObject({
19
+ // The unchanged JS binding exposes disabled facets as own undefined keys.
20
+ // Their JSON transport representation is absence; actual facet values are
21
+ // outside this interface-only profile and must still fail validation.
22
+ storage: z.undefined().optional(),
23
+ transientStorage: z.undefined().optional(),
24
+ disassembled: z.undefined().optional(),
25
+ basicBlocks: z.undefined().optional(),
26
+ controlFlowGraph: z.undefined().optional(),
27
+ // Upstream also extracts metadata when selectors are requested, regardless
28
+ // of its metadata flag. Retain its reported values without precision claims.
29
+ metadata: reportedMetadata.optional(),
30
+ functions: z
31
+ .array(z.strictObject({
32
+ selector: z.string().regex(/^[a-f0-9]{8}$/),
33
+ bytecodeOffset: offset,
34
+ dispatch: z.enum(["abi", "fallback"]),
35
+ arguments: z.string().optional(),
36
+ stateMutability: z.string().optional(),
37
+ }))
38
+ .optional(),
39
+ });
40
+ /** Preserve inference strings and unknown absence; selectors use the conventional 0x display prefix. */
41
+ export const projectEvmoleInterface = (raw) => {
42
+ const producer = evmoleInterfaceReplySchema.parse(raw);
43
+ return {
44
+ raw: producer,
45
+ functions: (producer.functions ?? []).map((fn) => ({
46
+ selector: `0x${fn.selector}`,
47
+ bytecode_offset: fn.bytecodeOffset,
48
+ dispatch: fn.dispatch,
49
+ inferred_arguments: fn.arguments ?? null,
50
+ inferred_state_mutability: fn.stateMutability ?? null,
51
+ })),
52
+ };
53
+ };