rea-agents 2.0.0 → 2.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 (246) hide show
  1. package/README.md +78 -32
  2. package/bridge/ghidra/ReaGhidraBridge.java +96 -11
  3. package/dist/application/ArtifactExtraction.js +1 -1
  4. package/dist/application/ArtifactInventory/classify.js +42 -0
  5. package/dist/application/ArtifactInventory/hash.js +43 -0
  6. package/dist/application/ArtifactInventory/reader.js +41 -0
  7. package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
  8. package/dist/application/ArtifactInventory/scanReader.js +124 -0
  9. package/dist/application/ArtifactInventory/types.js +10 -0
  10. package/dist/application/ArtifactInventory.js +9 -351
  11. package/dist/application/AuthorizedArtifactInventory.js +2 -2
  12. package/dist/application/BinarySession.js +47 -270
  13. package/dist/application/BinarySessionExecution.js +28 -0
  14. package/dist/application/BinarySessionOpen.js +39 -0
  15. package/dist/application/BinarySessionRecords.js +149 -0
  16. package/dist/application/BinarySessionStatus.js +75 -0
  17. package/dist/application/CapabilityInventory.js +24 -2
  18. package/dist/application/ClientRegistrationStatus.js +1 -1
  19. package/dist/application/CrossVersionInventory.js +8 -2
  20. package/dist/application/CrossVersionInvestigation.js +1 -23
  21. package/dist/application/CrossVersionInvestigationCollections.js +23 -0
  22. package/dist/application/DirectAnalysis.js +47 -44
  23. package/dist/application/Doctor.js +156 -238
  24. package/dist/application/DoctorDiagnostics.js +180 -0
  25. package/dist/application/ElectronBoundaryAnalysis.js +23 -7
  26. package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
  27. package/dist/application/EnhancedToolPagination.js +22 -0
  28. package/dist/application/EnhancedToolTypes.js +4 -0
  29. package/dist/application/EnhancedTools.js +20 -37
  30. package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
  31. package/dist/application/InvestigationWorkspaceStore.js +24 -10
  32. package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
  33. package/dist/application/JavaScriptArtifactFiles.js +6 -2
  34. package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
  35. package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
  36. package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
  37. package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
  38. package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
  39. package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
  40. package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
  41. package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
  42. package/dist/application/JavaScriptJsonModules.js +39 -0
  43. package/dist/application/JavaScriptModuleRelationships.js +262 -0
  44. package/dist/application/JavaScriptReplayPermission.js +16 -0
  45. package/dist/application/JavaScriptReplayService.js +182 -156
  46. package/dist/application/LinuxHopper.js +10 -0
  47. package/dist/application/MacHopper.js +22 -11
  48. package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
  49. package/dist/application/PermissionAuthority.js +106 -63
  50. package/dist/application/ProcessCaptureCapability.js +1 -1
  51. package/dist/application/ProcessCapturePermission.js +13 -0
  52. package/dist/application/ProcessCli.js +2 -12
  53. package/dist/application/ProcessHarness.js +1 -1
  54. package/dist/application/ProjectPermissionStore.js +48 -9
  55. package/dist/application/RealHopperAssertions.js +76 -0
  56. package/dist/application/ReconstructionCoverageService.js +69 -0
  57. package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
  58. package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
  59. package/dist/application/Setup.js +147 -259
  60. package/dist/application/SetupClientConfiguration.js +220 -0
  61. package/dist/application/SetupClients.js +24 -2
  62. package/dist/application/SetupPlan.js +123 -12
  63. package/dist/application/SetupSkill.js +26 -12
  64. package/dist/application/SupportedClients.js +1 -0
  65. package/dist/application/Uninstall.js +6 -3
  66. package/dist/application/WindowsCapabilities.js +86 -0
  67. package/dist/artifacts/AsarArtifactReader.js +11 -0
  68. package/dist/browser/BrowserProcessStartup.js +88 -0
  69. package/dist/browser/CdpCaptureDocuments.js +12 -8
  70. package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
  71. package/dist/browser/CdpCaptureEventHandlers.js +336 -0
  72. package/dist/browser/CdpCaptureEventHelpers.js +71 -0
  73. package/dist/browser/CdpCaptureEventState.js +1 -0
  74. package/dist/browser/CdpCaptureEventTypes.js +1 -0
  75. package/dist/browser/CdpCaptureEvents.js +29 -496
  76. package/dist/browser/CdpObservationSession.js +51 -8
  77. package/dist/browser/CdpPageCapture.js +12 -133
  78. package/dist/browser/CdpPageCaptureScripts.js +97 -0
  79. package/dist/browser/CdpPageCaptureWorkers.js +46 -0
  80. package/dist/browser/CdpWebMcpDiscovery.js +38 -14
  81. package/dist/browser/PngVisualDiff.js +9 -2
  82. package/dist/catalogIdentity.js +4 -0
  83. package/dist/cli/artifactCommands.js +82 -0
  84. package/dist/cli/coreAnalysisCommands.js +232 -0
  85. package/dist/cli/managedCommands.js +397 -0
  86. package/dist/cli/managedProjectGraphCommand.js +24 -0
  87. package/dist/cli/options.js +9 -0
  88. package/dist/cli/setupCommands.js +108 -0
  89. package/dist/cli/types.js +1 -0
  90. package/dist/cli/utilityCommands.js +122 -0
  91. package/dist/cli.js +10 -768
  92. package/dist/cliApplicationCommands.js +118 -4
  93. package/dist/cliBrowserAdvancedCommands.js +73 -16
  94. package/dist/cliBrowserCommands.js +39 -115
  95. package/dist/cliCommandNames.js +4 -0
  96. package/dist/cliElectronCommands.js +33 -62
  97. package/dist/cliEvidenceCommands.js +13 -2
  98. package/dist/cliInvestigationCommands.js +53 -10
  99. package/dist/cliObservationOptions.js +137 -0
  100. package/dist/cliPolicyCommands.js +80 -46
  101. package/dist/cliSetup.js +289 -0
  102. package/dist/config/environment.js +107 -0
  103. package/dist/config/parseConfig.js +228 -0
  104. package/dist/config/parsers.js +68 -0
  105. package/dist/config/permissions.js +30 -0
  106. package/dist/config/types.js +1 -0
  107. package/dist/config.js +1 -375
  108. package/dist/contracts/applicationToolContracts.js +134 -0
  109. package/dist/contracts/managedToolContracts.js +1 -1
  110. package/dist/contracts/managedWorkflowToolContracts.js +3 -3
  111. package/dist/contracts/providerSelection.js +2 -0
  112. package/dist/contracts/toolContracts.js +2 -2
  113. package/dist/contracts/toolEffects.js +14 -0
  114. package/dist/contracts/toolOutputSchemaGroups.js +232 -0
  115. package/dist/contracts/toolOutputSchemaPrimitives.js +327 -0
  116. package/dist/contracts/toolOutputSchemas.js +2 -550
  117. package/dist/domain/analysisErrorPresentation.js +234 -0
  118. package/dist/domain/analysisErrorProjection.js +284 -0
  119. package/dist/domain/artifactComparison.js +34 -15
  120. package/dist/domain/binaryTarget.js +87 -37
  121. package/dist/domain/browserObservation.js +1 -285
  122. package/dist/domain/browserObservationSchemas.js +286 -0
  123. package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
  124. package/dist/domain/errors.js +4 -486
  125. package/dist/domain/functionComparison.js +4 -165
  126. package/dist/domain/functionComparisonDimensions.js +164 -0
  127. package/dist/domain/javascriptApplicationVersionItems.js +18 -6
  128. package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
  129. package/dist/domain/javascriptExportInstrumentation.js +97 -0
  130. package/dist/domain/javascriptFeatureTraversal.js +19 -7
  131. package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
  132. package/dist/domain/javascriptSemanticAnalysis.js +386 -0
  133. package/dist/domain/javascriptSemanticIr.js +30 -0
  134. package/dist/domain/javascriptSemanticProjection.js +366 -0
  135. package/dist/domain/javascriptSemanticState.js +40 -0
  136. package/dist/domain/javascriptSemanticTraversal.js +22 -0
  137. package/dist/domain/javascriptSemanticValues.js +352 -0
  138. package/dist/domain/javascriptStaticAnalysis.js +5 -221
  139. package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
  140. package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
  141. package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
  142. package/dist/domain/knownPageCoverage.js +21 -0
  143. package/dist/domain/managedApplicationGraph.js +14 -364
  144. package/dist/domain/managedApplicationGraphCoverage.js +170 -0
  145. package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
  146. package/dist/domain/managedApplicationGraphNodes.js +336 -0
  147. package/dist/domain/managedArtifact.js +16 -8
  148. package/dist/domain/managedMemberComparison.js +37 -391
  149. package/dist/domain/managedMemberComparisonCoverage.js +72 -0
  150. package/dist/domain/managedMemberComparisonMatch.js +356 -0
  151. package/dist/domain/managedNativeVerification.js +27 -389
  152. package/dist/domain/managedNativeVerificationMatch.js +272 -0
  153. package/dist/domain/managedNativeVerificationSchemas.js +141 -0
  154. package/dist/domain/managedReconstruction.js +82 -69
  155. package/dist/domain/managedRuntimeCorrelation.js +12 -3
  156. package/dist/domain/nodeRuntimeCharacterization.js +66 -0
  157. package/dist/domain/permissionPolicy.js +2 -0
  158. package/dist/domain/reconstructionCoverage.js +387 -0
  159. package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
  160. package/dist/domain/reconstructionVerificationSchemas.js +8 -0
  161. package/dist/domain/runtimeCharacterization.js +85 -0
  162. package/dist/domain/webBundleAnalyzer.js +3 -409
  163. package/dist/domain/webBundleAnalyzerAst.js +77 -0
  164. package/dist/domain/webBundleAnalyzerInspection.js +307 -0
  165. package/dist/domain/webBundleAnalyzerResult.js +120 -0
  166. package/dist/dotnet/ManagedArtifactInspector.js +50 -29
  167. package/dist/dotnet/ManagedMemberInspector.js +51 -785
  168. package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
  169. package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
  170. package/dist/dotnet/ManagedMemberRows.js +120 -0
  171. package/dist/dotnet/ManagedMetadataInventory.js +42 -306
  172. package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
  173. package/dist/dotnet/ManagedMetadataLayout.js +48 -111
  174. package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
  175. package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
  176. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
  177. package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
  178. package/dist/dotnet/ManagedPeReader.js +59 -28
  179. package/dist/generatedPackageMetadata.js +2 -2
  180. package/dist/ghidra/GhidraClient.js +76 -91
  181. package/dist/ghidra/GhidraClientStartup.js +29 -0
  182. package/dist/ghidra/GhidraClientWire.js +34 -0
  183. package/dist/ghidra/GhidraDefaults.js +1 -1
  184. package/dist/ghidra/GhidraDiagnostics.js +6 -1
  185. package/dist/ghidra/GhidraInstallation.js +20 -15
  186. package/dist/ghidra/GhidraLauncher.js +93 -29
  187. package/dist/ghidra/GhidraProvider.js +61 -161
  188. package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
  189. package/dist/ghidra/GhidraSessionValues.js +2 -0
  190. package/dist/ghidra/GhidraSocketConnection.js +44 -7
  191. package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
  192. package/dist/ghidra/GhidraTransport.js +71 -0
  193. package/dist/identity.js +3 -2
  194. package/dist/main/messages.js +5 -0
  195. package/dist/main/reload.js +49 -0
  196. package/dist/main/shutdown.js +25 -0
  197. package/dist/main/startup.js +14 -0
  198. package/dist/main/state.js +26 -0
  199. package/dist/main/transport.js +61 -0
  200. package/dist/main/types.js +1 -0
  201. package/dist/main.js +35 -146
  202. package/dist/process/PrivateRuntimeRoot.js +3 -2
  203. package/dist/process/ProcessOwnership.js +35 -0
  204. package/dist/process/ProviderProcess.js +2 -0
  205. package/dist/replay/JavaScriptReplayWorker.js +64 -50
  206. package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
  207. package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
  208. package/dist/replay/ReplayOutcome.js +95 -0
  209. package/dist/replay/ReplayProcessLifecycle.js +71 -0
  210. package/dist/server/ProcessCaptureElicitation.js +157 -0
  211. package/dist/server/createServer.js +119 -54
  212. package/dist/server/registerApplicationTools/characterization.js +57 -0
  213. package/dist/server/registerApplicationTools/compareVersions.js +34 -0
  214. package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
  215. package/dist/server/registerApplicationTools/coverage.js +84 -0
  216. package/dist/server/registerApplicationTools/helpers.js +42 -0
  217. package/dist/server/registerApplicationTools/traceFeature.js +26 -0
  218. package/dist/server/registerApplicationTools/types.js +1 -0
  219. package/dist/server/registerApplicationTools.js +10 -112
  220. package/dist/server/registerBrowserTools.js +59 -83
  221. package/dist/server/registerElectronTools.js +31 -46
  222. package/dist/server/registerEnhancedTools.js +34 -42
  223. package/dist/server/registerEvidenceResources.js +54 -0
  224. package/dist/server/registerInvestigationTools/helpers.js +74 -0
  225. package/dist/server/registerInvestigationTools/types.js +1 -0
  226. package/dist/server/registerInvestigationTools.js +83 -116
  227. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
  228. package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
  229. package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
  230. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
  231. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
  232. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
  233. package/dist/server/registerManagedWorkflowTools/types.js +1 -0
  234. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
  235. package/dist/server/registerManagedWorkflowTools.js +10 -274
  236. package/dist/server/registerOfficialTools.js +73 -59
  237. package/dist/server/registerSessionRecordTools.js +137 -0
  238. package/dist/server/registerSessionStatusTool.js +2 -1
  239. package/dist/server/registerSessionTools.js +60 -164
  240. package/dist/server/sessionAvailabilityPolicy.js +10 -0
  241. package/dist/server/toolRegistrationOptions.js +101 -3
  242. package/dist/server/toolResult.js +5 -0
  243. package/package.json +10 -11
  244. package/skills/{rea-analysis → reverse-engineer-anything}/SKILL.md +20 -7
  245. package/scripts/prepare-node-pty.mjs +0 -35
  246. package/scripts/rebuild-native.mjs +0 -22
@@ -0,0 +1,352 @@
1
+ import * as t from "@babel/types";
2
+ import { resolveSemanticBindingState, } from "./javascriptSemanticState.js";
3
+ import { compareCodePoints, propertyName, stringValue, } from "./javascriptStaticAnalysisHelpers.js";
4
+ /** Evaluate one binding in the bounded constant-value lattice. */
5
+ export const evaluateSemanticBinding = (binding, state) => evaluateBinding(binding, { state, bindings: new Set(), depth: 0 });
6
+ /** Follow module provenance through destructuring, members, and aliases. */
7
+ export const evaluateSemanticProvenance = (binding, state) => provenanceForBinding(binding, { state, bindings: new Set(), depth: 0 });
8
+ const evaluateBinding = (binding, context) => {
9
+ if (context.bindings.has(binding.bindingId))
10
+ return { status: "cycle", reason: `Alias cycle at ${binding.name}.` };
11
+ if (context.depth >= context.state.limits.maxValueDepth)
12
+ return limitValue(context.state, "maxValueDepth");
13
+ if (binding.initializers.length === 0)
14
+ return {
15
+ status: "unknown",
16
+ reason: `Binding ${binding.name} has no constant initializer.`,
17
+ };
18
+ if (binding.initializers.length > 1)
19
+ return {
20
+ status: "ambiguous",
21
+ reason: `Binding ${binding.name} has multiple possible assignments.`,
22
+ };
23
+ const initializer = binding.initializers[0];
24
+ if (initializer === undefined)
25
+ return { status: "unknown", reason: "Missing binding initializer." };
26
+ const nested = nestedContext(context, binding.bindingId);
27
+ return projectValue(evaluateExpression(initializer.node, nested), initializer.projection);
28
+ };
29
+ const evaluateExpression = (node, context) => {
30
+ if (context.depth >= context.state.limits.maxValueDepth)
31
+ return limitValue(context.state, "maxValueDepth");
32
+ const literal = primitiveValue(node);
33
+ if (literal.found)
34
+ return { status: "literal", value: literal.value };
35
+ if (t.isIdentifier(node)) {
36
+ const binding = resolveSemanticBindingState(context.state, node, node.name);
37
+ return binding === undefined
38
+ ? { status: "unknown", reason: `Unbound identifier ${node.name}.` }
39
+ : evaluateBinding(binding, nestedContext(context));
40
+ }
41
+ if (t.isTemplateLiteral(node))
42
+ return evaluateTemplate(node, context);
43
+ if (t.isConditionalExpression(node))
44
+ return mergeValues([
45
+ evaluateExpression(node.consequent, nestedContext(context)),
46
+ evaluateExpression(node.alternate, nestedContext(context)),
47
+ ], context.state);
48
+ if (t.isLogicalExpression(node))
49
+ return mergeValues([
50
+ evaluateExpression(node.left, nestedContext(context)),
51
+ evaluateExpression(node.right, nestedContext(context)),
52
+ ], context.state);
53
+ if (t.isObjectExpression(node))
54
+ return evaluateObject(node, context);
55
+ if (t.isArrayExpression(node))
56
+ return evaluateArray(node, context);
57
+ if (t.isMemberExpression(node) || t.isOptionalMemberExpression(node))
58
+ return evaluateMember(node, context);
59
+ if (t.isBinaryExpression(node, { operator: "+" }))
60
+ return evaluateAddition(node, context);
61
+ if (t.isUnaryExpression(node))
62
+ return evaluateUnary(node, context);
63
+ if ((t.isTSAsExpression(node) ||
64
+ t.isTSTypeAssertion(node) ||
65
+ t.isTSNonNullExpression(node)) &&
66
+ t.isExpression(node.expression))
67
+ return evaluateExpression(node.expression, nestedContext(context));
68
+ return { status: "unknown", reason: `Unsupported ${node.type} value.` };
69
+ };
70
+ const evaluateTemplate = (node, context) => {
71
+ let candidates = [""];
72
+ for (let index = 0; index < node.quasis.length; index += 1) {
73
+ const quasi = node.quasis[index];
74
+ const text = quasi?.value.cooked ?? quasi?.value.raw ?? "";
75
+ candidates = candidates.map((prefix) => `${prefix}${text}`);
76
+ const expression = node.expressions[index];
77
+ if (expression === undefined)
78
+ continue;
79
+ const values = primitiveCandidates(evaluateExpression(expression, nestedContext(context)));
80
+ if (values === null)
81
+ return {
82
+ status: "unknown",
83
+ reason: "Template expression is not a bounded primitive.",
84
+ };
85
+ candidates = candidates.flatMap((prefix) => values.map((value) => `${prefix}${String(value)}`));
86
+ if (candidates.length > context.state.limits.maxUnionValues)
87
+ return limitValue(context.state, "maxUnionValues");
88
+ }
89
+ return primitiveSet(candidates, context.state);
90
+ };
91
+ const evaluateObject = (node, context) => {
92
+ const properties = [];
93
+ let unknownProperties = false;
94
+ for (const property of node.properties) {
95
+ if (t.isSpreadElement(property) || property.computed) {
96
+ unknownProperties = true;
97
+ continue;
98
+ }
99
+ const name = propertyName(property.key);
100
+ if (name === "" || !t.isObjectProperty(property)) {
101
+ unknownProperties = true;
102
+ continue;
103
+ }
104
+ if (properties.length >= context.state.limits.maxObjectProperties) {
105
+ markLimit(context.state, "maxObjectProperties");
106
+ unknownProperties = true;
107
+ continue;
108
+ }
109
+ properties.push({
110
+ name,
111
+ value: evaluateExpression(property.value, nestedContext(context)),
112
+ });
113
+ }
114
+ properties.sort((left, right) => compareCodePoints(left.name, right.name));
115
+ return { status: "object", properties, unknownProperties };
116
+ };
117
+ const evaluateArray = (node, context) => {
118
+ const items = [];
119
+ let unknownItems = false;
120
+ for (const element of node.elements) {
121
+ if (element === null || t.isSpreadElement(element)) {
122
+ unknownItems = true;
123
+ continue;
124
+ }
125
+ if (items.length >= context.state.limits.maxObjectProperties) {
126
+ markLimit(context.state, "maxObjectProperties");
127
+ unknownItems = true;
128
+ continue;
129
+ }
130
+ items.push(evaluateExpression(element, nestedContext(context)));
131
+ }
132
+ return { status: "array", items, unknownItems };
133
+ };
134
+ const evaluateMember = (node, context) => {
135
+ if (!t.isNode(node.object))
136
+ return { status: "unknown", reason: "Unsupported member base." };
137
+ const key = memberKey(node);
138
+ if (key === undefined)
139
+ return { status: "unknown", reason: "Dynamic member key." };
140
+ return projectValue(evaluateExpression(node.object, nestedContext(context)), [
141
+ key,
142
+ ]);
143
+ };
144
+ const evaluateAddition = (node, context) => {
145
+ const left = primitiveCandidates(evaluateExpression(node.left, nestedContext(context)));
146
+ const right = primitiveCandidates(evaluateExpression(node.right, nestedContext(context)));
147
+ if (left === null || right === null)
148
+ return { status: "unknown", reason: "Non-primitive addition." };
149
+ const values = left.flatMap((leftValue) => right.map((rightValue) => typeof leftValue === "number" && typeof rightValue === "number"
150
+ ? leftValue + rightValue
151
+ : `${String(leftValue)}${String(rightValue)}`));
152
+ return primitiveSet(values, context.state);
153
+ };
154
+ const evaluateUnary = (node, context) => {
155
+ const argument = primitiveCandidates(evaluateExpression(node.argument, nestedContext(context)));
156
+ if (argument === null)
157
+ return { status: "unknown", reason: "Non-primitive unary operand." };
158
+ if (node.operator === "!")
159
+ return primitiveSet(argument.map((value) => !value), context.state);
160
+ if (node.operator === "+")
161
+ return primitiveSet(argument.map((value) => Number(value)), context.state);
162
+ if (node.operator === "-")
163
+ return primitiveSet(argument.map((value) => -Number(value)), context.state);
164
+ return { status: "unknown", reason: `Unsupported unary ${node.operator}.` };
165
+ };
166
+ const projectValue = (value, projection) => {
167
+ let current = value;
168
+ for (const key of projection) {
169
+ if (key === null)
170
+ return {
171
+ status: "unknown",
172
+ reason: "Cannot project a dynamic property.",
173
+ };
174
+ if (current.status === "object" && typeof key === "string") {
175
+ const property = current.properties.find(({ name }) => name === key);
176
+ if (property === undefined)
177
+ return {
178
+ status: current.unknownProperties ? "unknown" : "unknown",
179
+ reason: `Object property ${key} was not observed.`,
180
+ };
181
+ current = property.value;
182
+ }
183
+ else if (current.status === "array" && typeof key === "number") {
184
+ const item = current.items[key];
185
+ if (item === undefined)
186
+ return {
187
+ status: "unknown",
188
+ reason: `Array item ${String(key)} missing.`,
189
+ };
190
+ current = item;
191
+ }
192
+ else
193
+ return {
194
+ status: "unknown",
195
+ reason: `Cannot project ${String(key)} from ${current.status}.`,
196
+ };
197
+ }
198
+ return current;
199
+ };
200
+ const provenanceForBinding = (binding, context) => {
201
+ if (context.bindings.has(binding.bindingId))
202
+ return provenance("cycle", [], `Alias cycle at ${binding.name}.`);
203
+ if (context.depth >= context.state.limits.maxValueDepth)
204
+ return limitProvenance(context.state, "maxValueDepth");
205
+ if (binding.directOrigins.length > 0)
206
+ return originsProvenance(binding.directOrigins, context.state);
207
+ if (binding.initializers.length === 0)
208
+ return provenance("local", [], null);
209
+ if (binding.initializers.length > 1)
210
+ return provenance("ambiguous", [], `Binding ${binding.name} has multiple possible assignments.`);
211
+ const initializer = binding.initializers[0];
212
+ if (initializer === undefined)
213
+ return provenance("unknown", [], "Missing binding initializer.");
214
+ if (initializer.projection.includes(null))
215
+ return provenance("unknown", [], "Dynamic provenance projection.");
216
+ const resolved = provenanceForExpression(initializer.node, nestedContext(context, binding.bindingId));
217
+ if (resolved.status !== "module" || initializer.projection.length === 0)
218
+ return resolved;
219
+ return originsProvenance(resolved.origins.map((origin) => ({
220
+ ...origin,
221
+ importedPath: [
222
+ ...origin.importedPath,
223
+ ...initializer.projection.map((segment) => String(segment)),
224
+ ],
225
+ })), context.state);
226
+ };
227
+ const provenanceForExpression = (node, context) => {
228
+ const required = requireOrigin(node);
229
+ if (required !== undefined)
230
+ return originsProvenance([required], context.state);
231
+ if (t.isIdentifier(node)) {
232
+ const binding = resolveSemanticBindingState(context.state, node, node.name);
233
+ return binding === undefined
234
+ ? provenance("unknown", [], `Unbound identifier ${node.name}.`)
235
+ : provenanceForBinding(binding, nestedContext(context));
236
+ }
237
+ if (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) {
238
+ if (!t.isNode(node.object))
239
+ return provenance("unknown", [], "Unsupported member base.");
240
+ const member = memberKey(node);
241
+ if (typeof member !== "string")
242
+ return provenance("unknown", [], "Dynamic provenance member.");
243
+ const base = provenanceForExpression(node.object, nestedContext(context));
244
+ return base.status !== "module"
245
+ ? base
246
+ : originsProvenance(base.origins.map((origin) => ({
247
+ ...origin,
248
+ importedPath: [...origin.importedPath, member],
249
+ })), context.state);
250
+ }
251
+ if (t.isConditionalExpression(node) || t.isLogicalExpression(node)) {
252
+ const left = t.isConditionalExpression(node) ? node.consequent : node.left;
253
+ const right = t.isConditionalExpression(node) ? node.alternate : node.right;
254
+ const candidates = [
255
+ provenanceForExpression(left, nestedContext(context)),
256
+ provenanceForExpression(right, nestedContext(context)),
257
+ ];
258
+ const origins = candidates.flatMap((candidate) => candidate.origins);
259
+ return origins.length > 0
260
+ ? provenance("ambiguous", uniqueOrigins(origins), "Multiple module origins.")
261
+ : provenance("unknown", [], "Conditional provenance is unresolved.");
262
+ }
263
+ return provenance("local", [], null);
264
+ };
265
+ const requireOrigin = (node) => {
266
+ if (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) {
267
+ if (!t.isNode(node.object))
268
+ return undefined;
269
+ const nested = requireOrigin(node.object);
270
+ const member = memberKey(node);
271
+ return nested === undefined || typeof member !== "string"
272
+ ? undefined
273
+ : { ...nested, importedPath: [...nested.importedPath, member] };
274
+ }
275
+ if (!t.isCallExpression(node) ||
276
+ !t.isIdentifier(node.callee, { name: "require" }))
277
+ return undefined;
278
+ const specifier = stringValue(node.arguments[0]);
279
+ return specifier === undefined ? undefined : { specifier, importedPath: [] };
280
+ };
281
+ const mergeValues = (values, state) => {
282
+ const primitives = values.flatMap((value) => primitiveCandidates(value) ?? []);
283
+ return primitives.length === values.length ||
284
+ values.every((value) => value.status === "union" || value.status === "literal")
285
+ ? primitiveSet(primitives, state)
286
+ : { status: "ambiguous", reason: "Branches have incompatible values." };
287
+ };
288
+ const primitiveSet = (values, state) => {
289
+ const unique = [
290
+ ...new Map(values.map((value) => [primitiveKey(value), value])).values(),
291
+ ].sort((left, right) => compareCodePoints(primitiveKey(left), primitiveKey(right)));
292
+ if (unique.length > state.limits.maxUnionValues)
293
+ return limitValue(state, "maxUnionValues");
294
+ const only = unique[0];
295
+ return unique.length === 1 && only !== undefined
296
+ ? { status: "literal", value: only }
297
+ : { status: "union", values: unique };
298
+ };
299
+ const primitiveCandidates = (value) => value.status === "literal"
300
+ ? [value.value]
301
+ : value.status === "union"
302
+ ? value.values
303
+ : null;
304
+ const primitiveValue = (node) => {
305
+ if (t.isStringLiteral(node) || t.isNumericLiteral(node))
306
+ return { found: true, value: node.value };
307
+ if (t.isBooleanLiteral(node))
308
+ return { found: true, value: node.value };
309
+ if (t.isNullLiteral(node))
310
+ return { found: true, value: null };
311
+ return { found: false };
312
+ };
313
+ const memberKey = (node) => {
314
+ if (!node.computed)
315
+ return propertyName(node.property) || undefined;
316
+ if (t.isStringLiteral(node.property) || t.isNumericLiteral(node.property))
317
+ return node.property.value;
318
+ return undefined;
319
+ };
320
+ const originsProvenance = (origins, state) => {
321
+ const unique = uniqueOrigins(origins);
322
+ if (unique.length > state.limits.maxUnionValues)
323
+ return limitProvenance(state, "maxUnionValues");
324
+ return unique.length === 1
325
+ ? provenance("module", unique, null)
326
+ : provenance("ambiguous", unique, "Multiple module origins.");
327
+ };
328
+ const uniqueOrigins = (origins) => [
329
+ ...new Map(origins.map((origin) => [originKey(origin), origin])).values(),
330
+ ].sort((left, right) => compareCodePoints(originKey(left), originKey(right)));
331
+ const provenance = (status, origins, reason) => ({ status, origins, reason });
332
+ const limitValue = (state, limit) => {
333
+ markLimit(state, limit);
334
+ return { status: "limit-reached", reason: `${limit} reached.` };
335
+ };
336
+ const limitProvenance = (state, limit) => {
337
+ markLimit(state, limit);
338
+ return provenance("limit-reached", [], `${limit} reached.`);
339
+ };
340
+ const markLimit = (state, limit) => {
341
+ state.limitsReached.add(limit);
342
+ state.omittedCount += 1;
343
+ };
344
+ const nestedContext = (context, bindingId) => ({
345
+ state: context.state,
346
+ depth: context.depth + 1,
347
+ bindings: bindingId === undefined
348
+ ? context.bindings
349
+ : new Set([...context.bindings, bindingId]),
350
+ });
351
+ const primitiveKey = (value) => `${value === null ? "null" : typeof value}:${JSON.stringify(value)}`;
352
+ const originKey = (origin) => `${origin.specifier}\0${origin.importedPath.join("\0")}`;
@@ -1,10 +1,11 @@
1
1
  import { parse } from "@babel/parser";
2
2
  import * as t from "@babel/types";
3
- import { collectJavaScriptExports, fingerprintJavaScriptAst, } from "./javascriptAstFingerprint.js";
4
- import { STATIC_ROUTE_CALL_NAMES, argumentValue, calleeName, chunkRuntime, compareCodePoints, detectVendors, endpointArgument, failedJavaScriptStaticAnalysis, factoryRequireName, moduleFactory, modulePropertyName, prefixedArgument, propertyName, range, rangeForOffsets, registrationKey, sanitizeCandidate, sha256Text, sortedUnique, sourceSlice, staticArrayValues, staticPath, storageKind, stringValue, } from "./javascriptStaticAnalysisHelpers.js";
5
- import { createJavaScriptAnalysisAccumulator, } from "./javascriptStaticAnalysisState.js";
6
- import { addBoundedFinding, addLocatedFinding, finalizeLocatedFindings, moduleAtOffset, } from "./javascriptStaticAnalysisFindings.js";
7
3
  import { inspectElectronStaticNode } from "./electronStaticAnalysis.js";
4
+ import { detectVendors, failedJavaScriptStaticAnalysis, registrationKey, sortedUnique, stringValue, } from "./javascriptStaticAnalysisHelpers.js";
5
+ import { addReference, addSourceMapDirectives, inspectCall, inspectRouteProperty, inspectRoleProperty, } from "./javascriptStaticAnalysisCalls.js";
6
+ import { inspectBundlerRegistration } from "./javascriptStaticAnalysisBundler.js";
7
+ import { finalizeLocatedFindings } from "./javascriptStaticAnalysisFindings.js";
8
+ import { createJavaScriptAnalysisAccumulator, } from "./javascriptStaticAnalysisState.js";
8
9
  /** Parse one bounded JavaScript artifact and recover static structure only. */
9
10
  export const analyzeJavaScriptStaticSource = (source, limits) => {
10
11
  let file;
@@ -127,220 +128,3 @@ const inspectNode = (source, node, accumulator, limits) => {
127
128
  inspectRoleProperty(node, findings);
128
129
  }
129
130
  };
130
- const inspectCall = (node, context) => {
131
- const { accumulator } = context;
132
- const name = calleeName(node.callee);
133
- const first = stringValue(node.arguments[0]);
134
- const module = moduleAtOffset(node.start, accumulator.modules);
135
- const moduleRequire = module?.requireName !== null && name === module?.requireName;
136
- if (name === "require" ||
137
- name.endsWith(".require") ||
138
- name.includes("__webpack_require__") ||
139
- moduleRequire)
140
- addReference(context, {
141
- node,
142
- kind: "require",
143
- specifier: argumentValue(node.arguments[0]),
144
- });
145
- if (name.endsWith(".e") && name.includes("require"))
146
- addReference(context, {
147
- node,
148
- kind: "dynamic-import",
149
- specifier: prefixedArgument("chunk:", node.arguments[0]),
150
- });
151
- if (name === "Worker" || name.endsWith(".Worker"))
152
- addReference(context, { node, kind: "worker", specifier: first });
153
- if (name.endsWith("serviceWorker.register"))
154
- addReference(context, { node, kind: "service-worker", specifier: first });
155
- inspectEndpointCall(node, name, first, context);
156
- inspectStorageCall(node, name, first, context);
157
- if (name.endsWith("loadFile") && first !== undefined)
158
- addLocatedFinding(context, {
159
- collection: accumulator.roles,
160
- key: `role\0renderer\0${first}`,
161
- node,
162
- value: {
163
- role: "renderer",
164
- path: first,
165
- mechanism: `call:${name}`,
166
- module_key: null,
167
- location: range(node),
168
- },
169
- });
170
- };
171
- const inspectBundlerRegistration = (source, call, accumulator, limits) => {
172
- const runtime = chunkRuntime(call);
173
- const entry = call.arguments[0];
174
- if (runtime === undefined || !t.isArrayExpression(entry))
175
- return;
176
- const chunkIds = entry.elements[0];
177
- const table = entry.elements[1];
178
- if (!t.isArrayExpression(chunkIds) || !t.isObjectExpression(table))
179
- return;
180
- const modules = [];
181
- for (const property of table.properties) {
182
- const factory = moduleFactory(property);
183
- if (factory === undefined)
184
- continue;
185
- if (accumulator.moduleCount >= limits.maxModules) {
186
- accumulator.droppedFindings += 1;
187
- continue;
188
- }
189
- accumulator.moduleCount += 1;
190
- const key = modulePropertyName(property);
191
- if (key.startsWith("[computed@") || key.startsWith("[unknown@"))
192
- accumulator.unknownFindings += 1;
193
- const exactSource = sourceSlice(source, factory);
194
- const fingerprint = fingerprintJavaScriptAst(factory, Math.min(limits.maxAstNodes, 100_000));
195
- const exportsValue = collectJavaScriptExports(factory, 256);
196
- if (fingerprint.truncated || exportsValue.truncated) {
197
- accumulator.droppedFindings += 1;
198
- accumulator.structuralTruncation = true;
199
- }
200
- modules.push({
201
- module_key: key,
202
- source_sha256: sha256Text(exactSource),
203
- structural_fingerprint_sha256: fingerprint.truncated
204
- ? null
205
- : fingerprint.sha256,
206
- structural_fingerprint_algorithm: fingerprint.truncated
207
- ? null
208
- : "babel-ast-v1",
209
- structural_fingerprint_status: fingerprint.truncated
210
- ? "truncated"
211
- : "complete",
212
- exports: exportsValue.values,
213
- exports_truncated: exportsValue.truncated,
214
- location: range(factory),
215
- });
216
- if (typeof factory.start === "number" && typeof factory.end === "number")
217
- accumulator.modules.push({
218
- start: factory.start,
219
- end: factory.end,
220
- key,
221
- requireName: factoryRequireName(factory),
222
- });
223
- }
224
- const chunkKeys = staticArrayValues(chunkIds, Math.min(256, limits.maxFindings));
225
- if (chunkKeys.omitted > 0) {
226
- accumulator.droppedFindings += chunkKeys.omitted;
227
- accumulator.structuralTruncation = true;
228
- }
229
- accumulator.unknownFindings += chunkKeys.unknown;
230
- const registration = {
231
- bundler: runtime.toLowerCase().includes("rspack")
232
- ? "rspack"
233
- : "webpack",
234
- runtime,
235
- chunk_keys: chunkKeys.values,
236
- omitted_chunk_keys: chunkKeys.omitted,
237
- unknown_chunk_keys: chunkKeys.unknown,
238
- modules: modules.sort((left, right) => compareCodePoints(left.module_key, right.module_key)),
239
- location: range(call),
240
- };
241
- addBoundedFinding(accumulator, `registration\0${registrationKey(registration)}`, limits.maxFindings, () => accumulator.registrations.push(registration));
242
- };
243
- const inspectEndpointCall = (node, name, first, context) => {
244
- const route = STATIC_ROUTE_CALL_NAMES.some((candidate) => name === candidate || name.endsWith(`.${candidate}`));
245
- if (route && first !== undefined)
246
- addEndpoint(context, {
247
- node,
248
- kind: "route",
249
- value: first,
250
- mechanism: `call:${name}`,
251
- });
252
- const endpoint = endpointArgument(name, node.arguments);
253
- if (endpoint !== undefined)
254
- addEndpoint(context, {
255
- node,
256
- kind: "network",
257
- value: endpoint,
258
- mechanism: `call:${name}`,
259
- });
260
- };
261
- const inspectRouteProperty = (node, context) => {
262
- const key = propertyName(node.key);
263
- if ((key === "path" || key === "route") && t.isStringLiteral(node.value))
264
- addEndpoint(context, {
265
- node,
266
- kind: "route",
267
- value: node.value.value,
268
- mechanism: `property:${key}`,
269
- });
270
- };
271
- const inspectRoleProperty = (node, context) => {
272
- if (propertyName(node.key) !== "preload")
273
- return;
274
- const path = staticPath(node.value);
275
- if (path === undefined)
276
- return;
277
- addLocatedFinding(context, {
278
- collection: context.accumulator.roles,
279
- key: `role\0preload\0${path}`,
280
- node,
281
- value: {
282
- role: "preload",
283
- path,
284
- mechanism: "property:preload",
285
- module_key: null,
286
- location: range(node),
287
- },
288
- });
289
- };
290
- const inspectStorageCall = (node, name, first, context) => {
291
- const storage = storageKind(name);
292
- if (storage === undefined)
293
- return;
294
- addLocatedFinding(context, {
295
- collection: context.accumulator.storage,
296
- key: `storage\0${storage}\0${first ?? ""}`,
297
- node,
298
- value: {
299
- kind: storage,
300
- name: first ?? null,
301
- mechanism: `call:${name}`,
302
- module_key: null,
303
- location: range(node),
304
- },
305
- });
306
- };
307
- const addReference = (context, input) => {
308
- const boundedSpecifier = input.specifier?.slice(0, 4_096) ?? null;
309
- const expression = boundedSpecifier === null
310
- ? sourceSlice(context.source, input.node).slice(0, 4_096)
311
- : null;
312
- addLocatedFinding(context, {
313
- collection: context.accumulator.references,
314
- key: `reference\0${input.kind}\0${boundedSpecifier ?? expression}`,
315
- node: input.node,
316
- value: {
317
- kind: input.kind,
318
- specifier: boundedSpecifier,
319
- expression,
320
- module_key: null,
321
- location: range(input.node),
322
- },
323
- });
324
- };
325
- const addEndpoint = (context, input) => addLocatedFinding(context, {
326
- collection: context.accumulator.endpoints,
327
- key: `endpoint\0${input.kind}\0${input.value}`,
328
- node: input.node,
329
- value: {
330
- kind: input.kind,
331
- value: sanitizeCandidate(input.value),
332
- mechanism: input.mechanism,
333
- module_key: null,
334
- location: range(input.node),
335
- },
336
- });
337
- const addSourceMapDirectives = (source, accumulator, maximum) => {
338
- for (const match of source.matchAll(/\/\/[#@]\s*sourceMappingURL\s*=\s*([^\s]+)/gu)) {
339
- const declared = match[1]?.slice(0, 4_096);
340
- if (declared === undefined)
341
- continue;
342
- const start = match.index;
343
- const location = rangeForOffsets(source, start, start + match[0].length);
344
- addBoundedFinding(accumulator, `source-map\0${declared}`, maximum, () => accumulator.sourceMaps.push({ declared_url: declared, location }));
345
- }
346
- };