rea-agents 1.6.0 → 2.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 (238) hide show
  1. package/README.md +157 -66
  2. package/bridge/ghidra/ReaGhidraBridge.java +2075 -0
  3. package/bridge/hopper_bridge.py +13 -3
  4. package/dist/application/AbortablePromise.js +25 -0
  5. package/dist/application/AnalysisProvider.js +3 -0
  6. package/dist/application/AnalysisProviderEvaluation.js +60 -0
  7. package/dist/application/AnalysisProviderRegistry.js +228 -0
  8. package/dist/application/AnalysisSnapshotCache.js +41 -21
  9. package/dist/application/AnalysisSnapshotFiles.js +5 -6
  10. package/dist/application/BinarySession.js +218 -101
  11. package/dist/application/CapabilityInventory.js +18 -0
  12. package/dist/application/CompositeProvider.js +20 -8
  13. package/dist/application/CrossVersionInvestigation.js +10 -6
  14. package/dist/application/DirectAnalysis.js +49 -35
  15. package/dist/application/Doctor.js +110 -8
  16. package/dist/application/ElectronBoundaryAnalysis.js +96 -0
  17. package/dist/application/ElectronBoundaryGraph.js +9 -0
  18. package/dist/application/ElectronBoundaryGraphContext.js +62 -0
  19. package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
  20. package/dist/application/ElectronBoundaryGraphNative.js +86 -0
  21. package/dist/application/ElectronBoundaryGraphWindows.js +199 -0
  22. package/dist/application/EnhancedTools.js +39 -14
  23. package/dist/application/InvestigationProviders.js +41 -0
  24. package/dist/application/JavaScriptApplicationEvidence.js +26 -0
  25. package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
  26. package/dist/application/JavaScriptApplicationService.js +74 -0
  27. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
  28. package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
  29. package/dist/application/JavaScriptArtifactAnalysis.js +305 -0
  30. package/dist/application/JavaScriptArtifactAnalysisTypes.js +1 -0
  31. package/dist/application/JavaScriptArtifactFiles.js +231 -0
  32. package/dist/application/JavaScriptArtifactGraphAccumulator.js +54 -0
  33. package/dist/application/JavaScriptArtifactGraphBuilder.js +144 -0
  34. package/dist/application/JavaScriptArtifactGraphContext.js +205 -0
  35. package/dist/application/JavaScriptArtifactGraphDocuments.js +108 -0
  36. package/dist/application/JavaScriptArtifactGraphEvidence.js +99 -0
  37. package/dist/application/JavaScriptArtifactGraphFindings.js +271 -0
  38. package/dist/application/JavaScriptArtifactGraphStructure.js +409 -0
  39. package/dist/application/JavaScriptArtifactReconstruction.js +77 -0
  40. package/dist/application/JavaScriptArtifactReconstructionInput.js +18 -0
  41. package/dist/application/JavaScriptReplayPlanning.js +201 -0
  42. package/dist/application/JavaScriptReplayService.js +266 -0
  43. package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
  44. package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
  45. package/dist/application/MacHopper.js +20 -4
  46. package/dist/application/ManagedApplicationGraphService.js +55 -0
  47. package/dist/application/ManagedMemberComparisonService.js +122 -0
  48. package/dist/application/ManagedNativeVerificationService.js +39 -0
  49. package/dist/application/ManagedReconstructionService.js +58 -0
  50. package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
  51. package/dist/application/PermissionAuthority.js +1 -1
  52. package/dist/application/ProcessCaptureLifecycle.js +1 -1
  53. package/dist/application/ProcessHarness.js +1 -1
  54. package/dist/application/ProcessSampling.js +16 -12
  55. package/dist/application/ProjectPermissionStore.js +1 -0
  56. package/dist/application/SessionProviderRouter.js +219 -0
  57. package/dist/application/Setup.js +84 -60
  58. package/dist/application/SetupClients.js +1 -1
  59. package/dist/application/SetupPlan.js +9 -2
  60. package/dist/application/SupportedClients.js +40 -16
  61. package/dist/application/Upgrade.js +1 -1
  62. package/dist/application/runtime.js +11 -6
  63. package/dist/artifacts/AsarArtifactReader.js +23 -3
  64. package/dist/browser/CdpBrowserProvider.js +4 -2
  65. package/dist/browser/CdpCaptureEvents.js +49 -0
  66. package/dist/browser/CdpElectronInspection.js +106 -162
  67. package/dist/browser/CdpElectronProvider.js +9 -3
  68. package/dist/browser/CdpElectronScriptEvents.js +69 -0
  69. package/dist/browser/CdpElectronScripts.js +94 -0
  70. package/dist/browser/CdpElectronWorkers.js +56 -0
  71. package/dist/browser/CdpEndpoint.js +14 -1
  72. package/dist/browser/CdpPageCapture.js +8 -4
  73. package/dist/catalogIdentity.js +6 -42
  74. package/dist/cli.js +446 -34
  75. package/dist/cliApplicationCommands.js +62 -0
  76. package/dist/cliBrowserAdvancedCommands.js +5 -4
  77. package/dist/cliBrowserCommands.js +5 -4
  78. package/dist/cliCommandNames.js +56 -0
  79. package/dist/cliElectronCommands.js +106 -3
  80. package/dist/cliEvidenceCommands.js +4 -3
  81. package/dist/cliInvestigationCommands.js +2 -1
  82. package/dist/cliJsonInput.js +54 -0
  83. package/dist/cliPolicyCommands.js +2 -1
  84. package/dist/cliProcessCommands.js +3 -2
  85. package/dist/config.js +101 -2
  86. package/dist/contracts/applicationToolContracts.js +91 -0
  87. package/dist/contracts/artifactToolContracts.js +5 -9
  88. package/dist/contracts/browserToolContracts.js +14 -62
  89. package/dist/contracts/electronToolContracts.js +45 -19
  90. package/dist/contracts/enhancedInputs.js +2 -2
  91. package/dist/contracts/errorSchemas.js +1 -0
  92. package/dist/contracts/investigationExamples.js +0 -6
  93. package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
  94. package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
  95. package/dist/contracts/managedToolContracts.js +153 -0
  96. package/dist/contracts/managedWorkflowExamples.js +346 -0
  97. package/dist/contracts/managedWorkflowToolContracts.js +203 -0
  98. package/dist/contracts/nativeToolContracts.js +2 -6
  99. package/dist/contracts/promptContracts.js +18 -2
  100. package/dist/contracts/providerSelection.js +28 -0
  101. package/dist/contracts/sessionLifecycleInputs.js +2 -0
  102. package/dist/contracts/toolContractExamples.js +10 -25
  103. package/dist/contracts/toolContracts.js +69 -65
  104. package/dist/contracts/toolEffects.js +160 -0
  105. package/dist/contracts/toolOutputSchemas.js +152 -42
  106. package/dist/doctorRuntime.js +47 -0
  107. package/dist/domain/analysisProfile.js +78 -0
  108. package/dist/domain/analysisSnapshot.js +92 -46
  109. package/dist/domain/artifactComparison.js +3 -4
  110. package/dist/domain/artifactGraph.js +1 -0
  111. package/dist/domain/binaryTarget.js +4 -29
  112. package/dist/domain/browserObservation.js +3 -0
  113. package/dist/domain/bundleComparison.js +4 -4
  114. package/dist/domain/electronObservation.js +13 -0
  115. package/dist/domain/electronStaticAnalysis.js +9 -0
  116. package/dist/domain/electronStaticAnalysisBrowser.js +194 -0
  117. package/dist/domain/electronStaticAnalysisIpc.js +171 -0
  118. package/dist/domain/electronStaticAnalysisNative.js +164 -0
  119. package/dist/domain/electronStaticAnalysisTypes.js +1 -0
  120. package/dist/domain/electronStaticAnalysisValues.js +103 -0
  121. package/dist/domain/errors.js +148 -7
  122. package/dist/domain/evidence.js +44 -5
  123. package/dist/domain/evidenceBundle.js +9 -7
  124. package/dist/domain/functionComparison.js +9 -3
  125. package/dist/domain/functionComparisonNormalization.js +37 -0
  126. package/dist/domain/functionComparisonSchemas.js +3 -8
  127. package/dist/domain/functionDossierEvidence.js +4 -1
  128. package/dist/domain/hopperValues.js +66 -9
  129. package/dist/domain/inputIssueProjection.js +52 -0
  130. package/dist/domain/investigationWorkspace.js +2 -1
  131. package/dist/domain/javascriptApplicationAnalysis.js +155 -0
  132. package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
  133. package/dist/domain/javascriptApplicationEvidenceSchemas.js +379 -0
  134. package/dist/domain/javascriptApplicationGraph.js +282 -0
  135. package/dist/domain/javascriptApplicationGraphSchemas.js +139 -0
  136. package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
  137. package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
  138. package/dist/domain/javascriptApplicationVersionItems.js +221 -0
  139. package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
  140. package/dist/domain/javascriptAstFingerprint.js +143 -0
  141. package/dist/domain/javascriptFeatureSeed.js +140 -0
  142. package/dist/domain/javascriptFeatureTrace.js +232 -0
  143. package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
  144. package/dist/domain/javascriptFeatureTraversal.js +88 -0
  145. package/dist/domain/javascriptNativeHandoff.js +85 -0
  146. package/dist/domain/javascriptReplay.js +361 -0
  147. package/dist/domain/javascriptRuntimeLoadState.js +106 -0
  148. package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
  149. package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
  150. package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
  151. package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
  152. package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
  153. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
  154. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
  155. package/dist/domain/javascriptRuntimeStaticCandidates.js +191 -0
  156. package/dist/domain/javascriptStaticAnalysis.js +346 -0
  157. package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
  158. package/dist/domain/javascriptStaticAnalysisHelpers.js +274 -0
  159. package/dist/domain/javascriptStaticAnalysisState.js +23 -0
  160. package/dist/domain/javascriptStaticAnalysisTypes.js +1 -0
  161. package/dist/domain/managedApplicationGraph.js +556 -0
  162. package/dist/domain/managedArtifact.js +444 -0
  163. package/dist/domain/managedMemberComparison.js +565 -0
  164. package/dist/domain/managedNativeVerification.js +408 -0
  165. package/dist/domain/managedReconstruction.js +183 -0
  166. package/dist/domain/managedRuntimeCorrelation.js +175 -0
  167. package/dist/domain/reconstructionVerificationSchemas.js +1 -3
  168. package/dist/dotnet/ManagedArtifactInspector.js +318 -0
  169. package/dist/dotnet/ManagedMemberInspector.js +887 -0
  170. package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
  171. package/dist/dotnet/ManagedMetadataInventory.js +368 -0
  172. package/dist/dotnet/ManagedMetadataLayout.js +322 -0
  173. package/dist/dotnet/ManagedNativeBoundaryInspector.js +391 -0
  174. package/dist/dotnet/ManagedPeReader.js +157 -0
  175. package/dist/dotnet/ManagedReaderFailure.js +10 -0
  176. package/dist/dotnet/ManagedStaticProvider.js +203 -0
  177. package/dist/generatedPackageMetadata.js +2 -2
  178. package/dist/ghidra/GhidraAnalysisProfile.js +37 -0
  179. package/dist/ghidra/GhidraClient.js +400 -0
  180. package/dist/ghidra/GhidraClientTypes.js +1 -0
  181. package/dist/ghidra/GhidraDefaults.js +20 -0
  182. package/dist/ghidra/GhidraDiagnostics.js +43 -0
  183. package/dist/ghidra/GhidraDoctor.js +59 -0
  184. package/dist/ghidra/GhidraFunctionValues.js +264 -0
  185. package/dist/ghidra/GhidraInstallation.js +239 -0
  186. package/dist/ghidra/GhidraInventoryValues.js +217 -0
  187. package/dist/ghidra/GhidraLauncher.js +139 -0
  188. package/dist/ghidra/GhidraProvider.js +366 -0
  189. package/dist/ghidra/GhidraRequestQueue.js +98 -0
  190. package/dist/ghidra/GhidraResponseBuffer.js +31 -0
  191. package/dist/ghidra/GhidraResponseRouter.js +24 -0
  192. package/dist/ghidra/GhidraSessionError.js +39 -0
  193. package/dist/ghidra/GhidraSessionValues.js +62 -0
  194. package/dist/ghidra/GhidraSocketConnection.js +46 -0
  195. package/dist/ghidra/protocol.js +69 -0
  196. package/dist/hopper/BridgeLauncher.js +19 -54
  197. package/dist/hopper/HopperAnalysisProfile.js +106 -0
  198. package/dist/hopper/HopperClient.js +154 -162
  199. package/dist/hopper/HopperProvider.js +99 -7
  200. package/dist/hopper/HopperSessionValues.js +27 -0
  201. package/dist/hopper/HopperSocketConnection.js +31 -0
  202. package/dist/main.js +14 -0
  203. package/dist/native/NativeMacOSProvider.js +3 -1
  204. package/dist/process/PendingOperations.js +59 -0
  205. package/dist/process/PrivateRuntimeRoot.js +33 -0
  206. package/dist/process/ProviderDeadline.js +95 -0
  207. package/dist/process/ProviderProcess.js +275 -0
  208. package/dist/replay/JavaScriptReplayWorker.js +286 -0
  209. package/dist/replay/LinuxJavaScriptReplayRunner.js +434 -0
  210. package/dist/replay/LinuxRuntimeClosure.js +46 -0
  211. package/dist/replay/LinuxSeccompPolicy.js +40 -0
  212. package/dist/replay/ReplayWorkerProtocol.js +55 -0
  213. package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
  214. package/dist/server/createServer.js +53 -0
  215. package/dist/server/promptCompletion.js +9 -3
  216. package/dist/server/registerApplicationTools.js +115 -0
  217. package/dist/server/registerArtifactComparisonTool.js +16 -9
  218. package/dist/server/registerBrowserTools.js +33 -8
  219. package/dist/server/registerBundleComparisonTool.js +17 -20
  220. package/dist/server/registerElectronTools.js +45 -3
  221. package/dist/server/registerEnhancedTools.js +67 -19
  222. package/dist/server/registerEvidenceTools.js +5 -1
  223. package/dist/server/registerFunctionComparisonTool.js +14 -7
  224. package/dist/server/registerInvestigationTools.js +21 -17
  225. package/dist/server/registerManagedTools.js +6 -0
  226. package/dist/server/registerManagedWorkflowTools.js +277 -0
  227. package/dist/server/registerOfficialTools.js +11 -8
  228. package/dist/server/registerProcessComparisonTool.js +25 -47
  229. package/dist/server/registerSessionStatusTool.js +7 -7
  230. package/dist/server/registerSessionTools.js +57 -87
  231. package/dist/server/sessionEvidence.js +14 -19
  232. package/dist/server/toolInputValidation.js +77 -0
  233. package/dist/server/toolRegistrationOptions.js +79 -2
  234. package/dist/server/toolResult.js +25 -17
  235. package/package.json +17 -7
  236. package/scripts/rea.mjs +36 -2
  237. package/skills/rea-analysis/SKILL.md +59 -3
  238. /package/dist/{application → process}/ProcessOwnership.js +0 -0
@@ -1,9 +1,50 @@
1
+ import { createAnalysisProfile, } from "../domain/analysisProfile.js";
2
+ /** Provider identity for deterministic composed analysis workflows. */
3
+ export const REA_WORKFLOW_PROVIDER = {
4
+ id: "rea-workflow",
5
+ name: "REA composed investigation workflow",
6
+ version: "1",
7
+ };
8
+ /** Commit a workflow result to the exact upstream deep-analysis profile. */
9
+ export const workflowAnalysisProfile = (upstream) => createAnalysisProfile(REA_WORKFLOW_PROVIDER, 1, {
10
+ upstream_analysis_profile: upstream,
11
+ });
1
12
  /** Provider identity for deterministic artifact inventories. */
2
13
  export const ARTIFACT_GRAPH_PROVIDER = {
3
14
  id: "rea-artifact-graph",
4
15
  name: "REA safe artifact graph provider",
5
16
  version: "1",
6
17
  };
18
+ /** Provider identity for execution-free managed PE/CLI analysis. */
19
+ export const MANAGED_STATIC_PROVIDER = {
20
+ id: "rea-dotnet-static",
21
+ name: "REA managed static analysis provider",
22
+ version: "1",
23
+ };
24
+ /** Provider identity for deterministic managed-code comparison workflows. */
25
+ export const MANAGED_WORKFLOW_PROVIDER = {
26
+ id: "rea-dotnet-workflows",
27
+ name: "REA managed-code workflows",
28
+ version: "1",
29
+ };
30
+ /** Provider identity for deterministic static JavaScript application analysis. */
31
+ export const JAVASCRIPT_APPLICATION_PROVIDER = {
32
+ id: "rea-javascript-application",
33
+ name: "REA JavaScript application analyzer",
34
+ version: "1",
35
+ };
36
+ /** Provider identity for static/passive-runtime JavaScript reconciliation. */
37
+ export const JAVASCRIPT_RUNTIME_RECONCILIATION_PROVIDER = {
38
+ id: "rea-javascript-runtime-reconciliation",
39
+ name: "REA JavaScript runtime reconciliation",
40
+ version: "1",
41
+ };
42
+ /** Provider identity for graph-native feature tracing and version comparison. */
43
+ export const JAVASCRIPT_APPLICATION_WORKFLOW_PROVIDER = {
44
+ id: "rea-javascript-application-workflows",
45
+ name: "REA JavaScript application workflows",
46
+ version: "1",
47
+ };
7
48
  /** Provider identity for deterministic cross-artifact comparisons. */
8
49
  export const ARTIFACT_COMPARISON_PROVIDER = {
9
50
  id: "rea-artifact-comparison",
@@ -0,0 +1,26 @@
1
+ import { createEvidence, } from "../domain/evidence.js";
2
+ import { jsonValueSchema } from "../domain/jsonValue.js";
3
+ import { JAVASCRIPT_APPLICATION_PROVIDER } from "./InvestigationProviders.js";
4
+ /** Create Evidence v2 for one deterministic local JavaScript application graph. */
5
+ export const createJavaScriptApplicationEvidence = (input, result) => createEvidence({
6
+ path: result.input_path,
7
+ sha256: result.root_artifact_sha256,
8
+ format: result.format,
9
+ }, JAVASCRIPT_APPLICATION_PROVIDER, {
10
+ predicateType: "rea.javascript-application-analysis/v1",
11
+ operation: "analyze_javascript_application",
12
+ parameters: parameters(input),
13
+ result: jsonValueSchema.parse(result),
14
+ rawResult: null,
15
+ confidence: "derived",
16
+ authority: "shipped-artifact",
17
+ environment: null,
18
+ limitations: result.limitations,
19
+ locations: [{ kind: "artifact-path", path: "artifact-root" }],
20
+ });
21
+ const parameters = (input) => ({
22
+ format: input.format,
23
+ approved: input.approved,
24
+ source_map_read_approved: input.source_map_read_approved,
25
+ limits: input.limits,
26
+ });
@@ -0,0 +1,89 @@
1
+ import { JAVASCRIPT_APPLICATION_PROVIDER, JAVASCRIPT_RUNTIME_RECONCILIATION_PROVIDER, MANAGED_WORKFLOW_PROVIDER, } from "./InvestigationProviders.js";
2
+ import { parseEvidence } from "../domain/evidence.js";
3
+ import { analyzeJavaScriptApplicationInputSchema, javascriptApplicationAnalysisResultSchema, } from "../domain/javascriptApplicationAnalysis.js";
4
+ import { javascriptRuntimeReconciliationResultSchema } from "../domain/javascriptRuntimeReconciliationSchemas.js";
5
+ import { managedApplicationGraphResultSchema } from "../domain/managedApplicationGraph.js";
6
+ /** Parse and authenticate one REA-produced JavaScript Application Graph Evidence. */
7
+ export const parseApplicationGraphEvidence = (input) => {
8
+ const evidence = parseEvidence(input);
9
+ if (evidence.operation === "analyze_javascript_application" &&
10
+ evidence.predicate_type === "rea.javascript-application-analysis/v1" &&
11
+ providerMatches(evidence, JAVASCRIPT_APPLICATION_PROVIDER))
12
+ return staticApplicationSource(evidence);
13
+ if (evidence.operation === "reconcile_javascript_runtime" &&
14
+ evidence.predicate_type === "rea.javascript-runtime-reconciliation/v1" &&
15
+ providerMatches(evidence, JAVASCRIPT_RUNTIME_RECONCILIATION_PROVIDER))
16
+ return staticRuntimeSource(evidence);
17
+ if (evidence.operation === "project_managed_application_graph" &&
18
+ evidence.predicate_type === "rea.managed-application-graph/v1" &&
19
+ providerMatches(evidence, MANAGED_WORKFLOW_PROVIDER))
20
+ return managedApplicationSource(evidence);
21
+ throw new TypeError("Application workflow requires authenticated analyze_javascript_application, reconcile_javascript_runtime, or project_managed_application_graph Evidence");
22
+ };
23
+ const staticApplicationSource = (evidence) => {
24
+ if (evidence.authority !== "shipped-artifact" ||
25
+ evidence.confidence !== "derived")
26
+ throw new TypeError("JavaScript application Evidence authority or confidence is invalid");
27
+ const result = javascriptApplicationAnalysisResultSchema.parse(evidence.normalized_result);
28
+ analyzeJavaScriptApplicationInputSchema.parse({
29
+ input_path: result.input_path,
30
+ ...evidence.parameters,
31
+ });
32
+ assertApplicationSubject(evidence, result);
33
+ return {
34
+ evidence,
35
+ graph: result.graph,
36
+ kind: "static-application",
37
+ rootArtifactSha256: result.root_artifact_sha256,
38
+ };
39
+ };
40
+ const staticRuntimeSource = (evidence) => {
41
+ if (evidence.authority !== "analyst-inference" ||
42
+ evidence.confidence !== "inferred")
43
+ throw new TypeError("JavaScript runtime reconciliation Evidence authority or confidence is invalid");
44
+ const result = javascriptRuntimeReconciliationResultSchema.parse(evidence.normalized_result);
45
+ if (result.evidence_links.some((evidenceId) => !evidence.evidence_links.includes(evidenceId)))
46
+ throw new TypeError("Runtime reconciliation result references Evidence outside its envelope");
47
+ const applicationLayer = result.static_layers.find(({ role }) => role === "application");
48
+ if (applicationLayer === undefined)
49
+ throw new TypeError("Runtime reconciliation application layer is missing");
50
+ return {
51
+ evidence,
52
+ graph: result.graph,
53
+ kind: "static-runtime-reconciliation",
54
+ rootArtifactSha256: applicationLayer.root_artifact_sha256,
55
+ };
56
+ };
57
+ const managedApplicationSource = (evidence) => {
58
+ if (evidence.authority !== "analyst-inference" ||
59
+ evidence.confidence !== "inferred")
60
+ throw new TypeError("Managed application graph Evidence authority or confidence is invalid");
61
+ const result = managedApplicationGraphResultSchema.parse(evidence.normalized_result);
62
+ if (result.evidence_links.some((evidenceId) => !evidence.evidence_links.includes(evidenceId)))
63
+ throw new TypeError("Managed application graph result references Evidence outside its envelope");
64
+ return {
65
+ evidence,
66
+ graph: result.graph,
67
+ kind: "managed-application",
68
+ rootArtifactSha256: result.root_artifact_sha256,
69
+ };
70
+ };
71
+ const assertApplicationSubject = (evidence, result) => {
72
+ if (evidence.subject === null ||
73
+ evidence.subject.digest.sha256 !== result.root_artifact_sha256 ||
74
+ evidence.subject.format !== result.format)
75
+ throw new TypeError("JavaScript application Evidence subject does not match its result");
76
+ };
77
+ const providerMatches = (evidence, provider) => evidence.provider.id === provider.id &&
78
+ evidence.provider.name === provider.name &&
79
+ evidence.provider.version === provider.version;
80
+ /** Parse unique, artifact-bound Evidence that may extend a native handoff. */
81
+ export const parseNativeApplicationEvidence = (inputs) => {
82
+ const parsed = inputs.map((input) => parseEvidence(input));
83
+ if (parsed.some(({ subject }) => subject === null))
84
+ throw new TypeError("Native handoff Evidence requires an artifact subject");
85
+ const ids = parsed.map(({ evidence_id: id }) => id);
86
+ if (new Set(ids).size !== ids.length)
87
+ throw new TypeError("Native handoff Evidence must be unique");
88
+ return parsed;
89
+ };
@@ -0,0 +1,74 @@
1
+ import { z } from "zod";
2
+ import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
3
+ import { analyzeJavaScriptApplicationInputSchema, javascriptApplicationAnalysisResultSchema, } from "../domain/javascriptApplicationAnalysis.js";
4
+ import { AnalysisCapabilityUnavailableError, AnalysisInputError, AnalysisProtocolError, ArtifactOperationError, PermissionRequiredError, } from "../domain/errors.js";
5
+ import { err, ok } from "../domain/result.js";
6
+ import { createJavaScriptApplicationEvidence } from "./JavaScriptApplicationEvidence.js";
7
+ import { reconstructJavaScriptArtifact } from "./JavaScriptArtifactReconstruction.js";
8
+ const OPERATION = "analyze_javascript_application";
9
+ /** Authorize and statically analyze one local JavaScript/Electron application. */
10
+ export const analyzeJavaScriptApplication = async (authority, rawInput, options = {}) => {
11
+ const parsed = analyzeJavaScriptApplicationInputSchema.safeParse(rawInput);
12
+ if (!parsed.success)
13
+ return err(new AnalysisInputError(OPERATION));
14
+ return analyzeJavaScriptApplicationValidated(authority, parsed.data, options);
15
+ };
16
+ /** Analyze input already parsed by a trusted adapter boundary. */
17
+ export const analyzeJavaScriptApplicationValidated = async (authority, input, options = {}) => {
18
+ if (authority === undefined)
19
+ return err(new AnalysisCapabilityUnavailableError("rea-javascript-application", OPERATION, "JavaScript application permission policy is not configured"));
20
+ const authorized = await authority.authorize({
21
+ capability: "investigation_input",
22
+ roots: [input.input_path],
23
+ executables: [],
24
+ environment_names: [],
25
+ network: "none",
26
+ mount: false,
27
+ operation_identity: `${OPERATION}:${input.input_path}`,
28
+ }, "read");
29
+ if (!authorized.ok)
30
+ return err(authorized.error instanceof PermissionRequiredError
31
+ ? authorized.error
32
+ : new ArtifactOperationError(OPERATION, "path", {
33
+ logicalPath: input.input_path,
34
+ declaredSha256: null,
35
+ calculatedSha256: null,
36
+ unpacked: false,
37
+ }));
38
+ await options.progress?.report({
39
+ phase: "analyze_javascript_application",
40
+ completed: 0,
41
+ total: 1,
42
+ message: "Inventorying and parsing approved application artifacts",
43
+ });
44
+ try {
45
+ const reconstructed = await reconstructJavaScriptArtifact({
46
+ input_path: input.input_path,
47
+ format: input.format,
48
+ source_map_read_approved: input.source_map_read_approved,
49
+ limits: input.limits,
50
+ }, options.signal);
51
+ const { electron_summary: summary, ...application } = reconstructed;
52
+ const result = javascriptApplicationAnalysisResultSchema.parse({
53
+ schema_version: 1,
54
+ ...application,
55
+ summary,
56
+ limitations: reconstructed.graph.limitations,
57
+ });
58
+ await options.progress?.report({
59
+ phase: "analyze_javascript_application",
60
+ completed: 1,
61
+ total: 1,
62
+ message: "Application graph and Electron boundaries reconstructed",
63
+ terminal: true,
64
+ });
65
+ return ok(createJavaScriptApplicationEvidence(input, result));
66
+ }
67
+ catch (cause) {
68
+ if (cause instanceof ArtifactReaderFailure)
69
+ return err(new ArtifactOperationError(OPERATION, cause.reason, cause.details));
70
+ if (cause instanceof z.ZodError)
71
+ return err(new AnalysisProtocolError("JavaScript application analysis produced an invalid result", { cause }));
72
+ return err(new ArtifactOperationError(OPERATION, "io"));
73
+ }
74
+ };
@@ -0,0 +1,29 @@
1
+ import { createEvidence, } from "../domain/evidence.js";
2
+ import { jsonValueSchema } from "../domain/jsonValue.js";
3
+ import { JAVASCRIPT_APPLICATION_WORKFLOW_PROVIDER } from "./InvestigationProviders.js";
4
+ /** Create derived Evidence for one bounded application-graph feature trace. */
5
+ export const createApplicationFeatureTraceEvidence = (parameters, result) => createEvidence(undefined, JAVASCRIPT_APPLICATION_WORKFLOW_PROVIDER, {
6
+ predicateType: "rea.application-feature-trace/v1",
7
+ operation: "trace_application_feature",
8
+ parameters,
9
+ result: jsonValueSchema.parse(result),
10
+ rawResult: null,
11
+ confidence: "inferred",
12
+ authority: "analyst-inference",
13
+ environment: null,
14
+ limitations: result.limitations,
15
+ evidenceLinks: result.evidence_links,
16
+ });
17
+ /** Create derived Evidence for one tiered application version comparison. */
18
+ export const createApplicationVersionComparisonEvidence = (parameters, result) => createEvidence(undefined, JAVASCRIPT_APPLICATION_WORKFLOW_PROVIDER, {
19
+ predicateType: "rea.application-version-comparison/v1",
20
+ operation: "compare_application_versions",
21
+ parameters,
22
+ result: jsonValueSchema.parse(result),
23
+ rawResult: null,
24
+ confidence: "inferred",
25
+ authority: "analyst-inference",
26
+ environment: null,
27
+ limitations: result.limitations,
28
+ evidenceLinks: result.evidence_links,
29
+ });
@@ -0,0 +1,90 @@
1
+ import { z } from "zod";
2
+ import { AnalysisInputError, AnalysisProtocolError, } from "../domain/errors.js";
3
+ import { projectInputIssues } from "../domain/inputIssueProjection.js";
4
+ import { compareJavaScriptApplicationVersions } from "../domain/javascriptApplicationVersionComparison.js";
5
+ import { compareApplicationVersionsInputSchema } from "../domain/javascriptApplicationVersionComparisonSchemas.js";
6
+ import { traceApplicationFeature } from "../domain/javascriptFeatureTrace.js";
7
+ import { traceApplicationFeatureInputSchema } from "../domain/javascriptFeatureTraceSchemas.js";
8
+ import { err, ok } from "../domain/result.js";
9
+ import { parseApplicationGraphEvidence, parseNativeApplicationEvidence, } from "./JavaScriptApplicationEvidenceGraph.js";
10
+ import { createApplicationFeatureTraceEvidence, createApplicationVersionComparisonEvidence, } from "./JavaScriptApplicationWorkflowEvidence.js";
11
+ /** Authenticate Evidence and derive one bounded cross-layer feature trace. */
12
+ export const traceApplicationFeatureEvidence = (rawInput) => {
13
+ const operation = "trace_application_feature";
14
+ const parsed = traceApplicationFeatureInputSchema.safeParse(rawInput);
15
+ if (!parsed.success)
16
+ return err(new AnalysisInputError(operation, undefined, projectInputIssues(parsed.error.issues, rawInput)));
17
+ return traceApplicationFeatureEvidenceValidated(parsed.data);
18
+ };
19
+ /** Derive one feature trace from input parsed by a trusted adapter. */
20
+ export const traceApplicationFeatureEvidenceValidated = (input) => {
21
+ const operation = "trace_application_feature";
22
+ try {
23
+ const source = parseApplicationGraphEvidence(input.application);
24
+ const nativeEvidence = parseNativeApplicationEvidence(input.native_observations);
25
+ const result = traceApplicationFeature({
26
+ sourceEvidenceId: source.evidence.evidence_id,
27
+ graph: source.graph,
28
+ nativeEvidence,
29
+ seed: input.seed,
30
+ direction: input.direction,
31
+ limits: input.limits,
32
+ });
33
+ return ok(createApplicationFeatureTraceEvidence({
34
+ application_evidence_id: source.evidence.evidence_id,
35
+ native_evidence_ids: nativeEvidence.map(({ evidence_id: id }) => id),
36
+ seed: input.seed,
37
+ direction: input.direction,
38
+ limits: input.limits,
39
+ }, result));
40
+ }
41
+ catch (cause) {
42
+ return workflowFailure(operation, cause);
43
+ }
44
+ };
45
+ /** Authenticate both graphs and derive a tiered cross-version change graph. */
46
+ export const compareApplicationVersionsEvidence = (rawInput) => {
47
+ const operation = "compare_application_versions";
48
+ const parsed = compareApplicationVersionsInputSchema.safeParse(rawInput);
49
+ if (!parsed.success)
50
+ return err(new AnalysisInputError(operation, undefined, projectInputIssues(parsed.error.issues, rawInput)));
51
+ return compareApplicationVersionsEvidenceValidated(parsed.data);
52
+ };
53
+ /** Compare versions from input parsed by a trusted adapter. */
54
+ export const compareApplicationVersionsEvidenceValidated = (input) => {
55
+ const operation = "compare_application_versions";
56
+ try {
57
+ const left = parseApplicationGraphEvidence(input.left);
58
+ const right = parseApplicationGraphEvidence(input.right);
59
+ const leftNative = parseNativeApplicationEvidence(input.left_native_observations);
60
+ const rightNative = parseNativeApplicationEvidence(input.right_native_observations);
61
+ const result = compareJavaScriptApplicationVersions({
62
+ left: {
63
+ evidenceId: left.evidence.evidence_id,
64
+ rootArtifactSha256: left.rootArtifactSha256,
65
+ graph: left.graph,
66
+ },
67
+ right: {
68
+ evidenceId: right.evidence.evidence_id,
69
+ rootArtifactSha256: right.rootArtifactSha256,
70
+ graph: right.graph,
71
+ },
72
+ leftNativeEvidence: leftNative,
73
+ rightNativeEvidence: rightNative,
74
+ limits: input.limits,
75
+ });
76
+ return ok(createApplicationVersionComparisonEvidence({
77
+ left_evidence_id: left.evidence.evidence_id,
78
+ right_evidence_id: right.evidence.evidence_id,
79
+ left_native_evidence_ids: leftNative.map(({ evidence_id: id }) => id),
80
+ right_native_evidence_ids: rightNative.map(({ evidence_id: id }) => id),
81
+ limits: input.limits,
82
+ }, result));
83
+ }
84
+ catch (cause) {
85
+ return workflowFailure(operation, cause);
86
+ }
87
+ };
88
+ const workflowFailure = (operation, cause) => err(cause instanceof z.ZodError || cause instanceof TypeError
89
+ ? new AnalysisInputError(operation)
90
+ : new AnalysisProtocolError("JavaScript application workflow produced an invalid result", { cause }));
@@ -0,0 +1,305 @@
1
+ import { createHash } from "node:crypto";
2
+ import { analyzeJavaScriptStaticSource } from "../domain/javascriptStaticAnalysis.js";
3
+ /** Analyze selected text files under one shared AST, finding, module, and time budget. */
4
+ export const analyzeJavaScriptArtifactFiles = (fileSet, input, now) => {
5
+ const state = emptyArtifactAnalysis();
6
+ const context = {
7
+ state,
8
+ input,
9
+ deadline: now() + input.limits.max_parse_milliseconds,
10
+ now,
11
+ };
12
+ for (const file of fileSet.files)
13
+ analyzeArtifactFile(file, context);
14
+ return finalizeArtifactAnalysis(state, input);
15
+ };
16
+ const finalizeArtifactAnalysis = (state, input) => {
17
+ const omittedHtmlFindings = Math.max(0, state.htmlScripts.length + state.findings - input.limits.max_findings);
18
+ const findings = Math.min(input.limits.max_findings, state.findings + state.htmlScripts.length);
19
+ const sourceMapTruncations = state.sourceMaps.filter(({ status }) => status === "truncated").length;
20
+ const truncatedScopes = state.truncatedScopes +
21
+ sourceMapTruncations +
22
+ (omittedHtmlFindings > 0 ? 1 : 0);
23
+ return {
24
+ files: state.files,
25
+ packages: state.packages,
26
+ html_scripts: state.htmlScripts.slice(0, input.limits.max_findings),
27
+ source_maps: state.sourceMaps,
28
+ visited_ast_nodes: state.visitedNodes,
29
+ findings,
30
+ modules: state.modules,
31
+ parse_failures: state.parseFailures,
32
+ truncated_scopes: truncatedScopes,
33
+ limitations: [
34
+ "JavaScript and HTML were parsed as inert text; bundle bootstrap code was never executed.",
35
+ "Static paths and relationships may remain unresolved when expressions are dynamic or obfuscated.",
36
+ ...(input.source_map_read_approved
37
+ ? []
38
+ : [
39
+ "Source maps were inventoried but their contents were not read without separate approval.",
40
+ ]),
41
+ ...(truncatedScopes === 0
42
+ ? []
43
+ : ["One or more static-analysis scopes reached an approved bound."]),
44
+ ],
45
+ };
46
+ };
47
+ const analyzeArtifactFile = (file, context) => {
48
+ const { state, input } = context;
49
+ if (file.kind === "package-json")
50
+ state.packages.push(parsePackage(file));
51
+ if (file.kind === "html" && file.text.included)
52
+ state.htmlScripts.push(...parseHtmlScripts(file.path, file.text.value, Math.max(0, input.limits.max_findings - state.findings)));
53
+ if (file.kind === "source-map")
54
+ addSourceMap(file, context);
55
+ if (file.kind !== "javascript" || !file.text.included) {
56
+ state.files.push({ file, javascript: null });
57
+ return;
58
+ }
59
+ const remainingNodes = input.limits.max_ast_nodes - state.visitedNodes;
60
+ const remainingFindings = input.limits.max_findings - state.findings;
61
+ const remainingModules = input.limits.max_modules - state.modules;
62
+ if (remainingNodes <= 0 ||
63
+ remainingFindings <= 0 ||
64
+ remainingModules <= 0 ||
65
+ context.now() > context.deadline) {
66
+ state.files.push({ file, javascript: null });
67
+ state.truncatedScopes += 1;
68
+ return;
69
+ }
70
+ const analysis = analyzeJavaScriptStaticSource(file.text.value, {
71
+ maxAstNodes: remainingNodes,
72
+ maxFindings: remainingFindings,
73
+ maxModules: remainingModules,
74
+ deadline: context.deadline,
75
+ now: context.now,
76
+ });
77
+ state.files.push({ file, javascript: analysis });
78
+ state.visitedNodes += analysis.visited_ast_nodes;
79
+ state.findings += findingCount(analysis);
80
+ state.modules += analysis.bundler_registrations.reduce((count, registration) => count + registration.modules.length, 0);
81
+ if (analysis.parse_status === "failed")
82
+ state.parseFailures += 1;
83
+ if (analysis.parse_status === "truncated")
84
+ state.truncatedScopes += 1;
85
+ };
86
+ const addSourceMap = (file, context) => {
87
+ const sourceMap = parseSourceMap(file, {
88
+ deadline: context.deadline,
89
+ now: context.now,
90
+ maximumSources: Math.max(0, context.input.limits.max_source_map_sources -
91
+ context.state.sourceMapSources),
92
+ });
93
+ context.state.sourceMaps.push(sourceMap);
94
+ context.state.sourceMapSources += sourceMap.sources.length;
95
+ };
96
+ const emptyArtifactAnalysis = () => ({
97
+ files: [],
98
+ packages: [],
99
+ htmlScripts: [],
100
+ sourceMaps: [],
101
+ visitedNodes: 0,
102
+ findings: 0,
103
+ modules: 0,
104
+ parseFailures: 0,
105
+ truncatedScopes: 0,
106
+ sourceMapSources: 0,
107
+ });
108
+ const parsePackage = (file) => {
109
+ if (!file.text.included)
110
+ return unavailablePackage(file, "Package metadata text was unavailable.");
111
+ let value;
112
+ try {
113
+ value = JSON.parse(file.text.value);
114
+ }
115
+ catch {
116
+ return invalidPackage(file, "package.json is not valid JSON.");
117
+ }
118
+ if (!isRecord(value))
119
+ return invalidPackage(file, "package.json root is not an object.");
120
+ return {
121
+ path: file.path,
122
+ sha256: file.sha256,
123
+ status: "included",
124
+ name: boundedString(value.name),
125
+ version: boundedString(value.version),
126
+ main: boundedString(value.main),
127
+ renderer: boundedString(value.renderer) ??
128
+ boundedString(value.browser) ??
129
+ boundedString(value.module),
130
+ limitation: null,
131
+ };
132
+ };
133
+ const invalidPackage = (file, limitation) => ({
134
+ ...unavailablePackage(file, limitation),
135
+ status: "invalid",
136
+ });
137
+ const unavailablePackage = (file, limitation) => ({
138
+ path: file.path,
139
+ sha256: file.sha256,
140
+ status: "unavailable",
141
+ name: null,
142
+ version: null,
143
+ main: null,
144
+ renderer: null,
145
+ limitation,
146
+ });
147
+ const parseHtmlScripts = (path, text, maximum) => {
148
+ const scripts = [];
149
+ const pattern = /<script\b[^>]*\bsrc\s*=\s*(["'])([^"']+)\1[^>]*>/giu;
150
+ for (const match of text.matchAll(pattern)) {
151
+ const script = match[2]?.slice(0, 4_096);
152
+ if (script === undefined || scripts.length >= maximum)
153
+ break;
154
+ const start = match.index;
155
+ scripts.push({
156
+ html_path: path,
157
+ script_path: script,
158
+ location: rangeForOffsets(text, start, start + match[0].length),
159
+ });
160
+ }
161
+ return scripts;
162
+ };
163
+ const parseSourceMap = (file, context) => {
164
+ if (!file.text.included)
165
+ return unavailableSourceMap(file);
166
+ if (context.now() > context.deadline)
167
+ return truncatedSourceMap(file, null, "Parse deadline reached before source-map decoding.");
168
+ let value;
169
+ try {
170
+ value = JSON.parse(file.text.value);
171
+ }
172
+ catch {
173
+ return invalidSourceMap(file, "Source map is not valid JSON.");
174
+ }
175
+ if (context.now() > context.deadline)
176
+ return truncatedSourceMap(file, null, "Parse deadline elapsed during source-map decoding.");
177
+ const maps = flattenSourceMaps(value, 10_000);
178
+ if (maps === undefined)
179
+ return invalidSourceMap(file, "Source map is not a bounded version 3 map.");
180
+ return collectSourceMapOriginals(file, maps, context);
181
+ };
182
+ const collectSourceMapOriginals = (file, maps, context) => {
183
+ const sources = [];
184
+ let total = 0;
185
+ for (const map of maps) {
186
+ const names = map.sources;
187
+ if (!Array.isArray(names))
188
+ return invalidSourceMap(file, "Source map has no sources array.");
189
+ const contents = Array.isArray(map.sourcesContent)
190
+ ? map.sourcesContent
191
+ : [];
192
+ const root = typeof map.sourceRoot === "string" ? map.sourceRoot : "";
193
+ for (const [index, raw] of names.entries()) {
194
+ if (total % 1_024 === 0 && context.now() > context.deadline)
195
+ return {
196
+ path: file.path,
197
+ sha256: file.sha256,
198
+ status: "truncated",
199
+ sources,
200
+ omitted_sources: null,
201
+ limitation: "Parse deadline elapsed during source-map traversal.",
202
+ };
203
+ if (typeof raw !== "string")
204
+ return invalidSourceMap(file, "Source map contains a non-string source name.");
205
+ total += 1;
206
+ if (sources.length >= context.maximumSources)
207
+ continue;
208
+ const content = typeof contents[index] === "string" ? contents[index] : null;
209
+ sources.push({
210
+ source: resolveSourceName(root, raw),
211
+ content,
212
+ content_sha256: content === null ? null : sha256(content),
213
+ });
214
+ }
215
+ }
216
+ const omitted = total - sources.length;
217
+ return {
218
+ path: file.path,
219
+ sha256: file.sha256,
220
+ status: omitted === 0 ? "included" : "truncated",
221
+ sources,
222
+ omitted_sources: omitted,
223
+ limitation: omitted === 0
224
+ ? null
225
+ : "Original-source inventory reached the approved source-map limit.",
226
+ };
227
+ };
228
+ const unavailableSourceMap = (file) => {
229
+ if (file.text.included)
230
+ throw new TypeError("Expected unavailable source-map text");
231
+ const notApproved = file.text.reason === "not-approved";
232
+ return {
233
+ path: file.path,
234
+ sha256: file.sha256,
235
+ status: notApproved ? "not-approved" : "invalid",
236
+ sources: [],
237
+ omitted_sources: 0,
238
+ limitation: notApproved
239
+ ? "Source-map content requires separate approval."
240
+ : "Source-map text was unavailable within approved limits.",
241
+ };
242
+ };
243
+ const flattenSourceMaps = (root, maximum) => {
244
+ if (!isRecord(root) || root.version !== 3)
245
+ return undefined;
246
+ const maps = [];
247
+ const pending = [root];
248
+ while (pending.length > 0) {
249
+ const map = pending.pop();
250
+ if (map === undefined || map.version !== 3)
251
+ return undefined;
252
+ if (Array.isArray(map.sections)) {
253
+ if (pending.length + maps.length + map.sections.length > maximum)
254
+ return undefined;
255
+ for (const section of map.sections) {
256
+ if (!isRecord(section) || !isRecord(section.map))
257
+ return undefined;
258
+ pending.push(section.map);
259
+ }
260
+ }
261
+ else
262
+ maps.push(map);
263
+ }
264
+ return maps;
265
+ };
266
+ const truncatedSourceMap = (file, omitted, limitation) => ({
267
+ path: file.path,
268
+ sha256: file.sha256,
269
+ status: "truncated",
270
+ sources: [],
271
+ omitted_sources: omitted,
272
+ limitation,
273
+ });
274
+ const invalidSourceMap = (file, limitation) => ({
275
+ path: file.path,
276
+ sha256: file.sha256,
277
+ status: "invalid",
278
+ sources: [],
279
+ omitted_sources: 0,
280
+ limitation,
281
+ });
282
+ const findingCount = (analysis) => analysis.references.length +
283
+ analysis.endpoints.length +
284
+ analysis.storage.length +
285
+ analysis.role_paths.length +
286
+ analysis.source_map_urls.length +
287
+ analysis.bundler_registrations.length +
288
+ analysis.electron.browser_windows.length +
289
+ analysis.electron.context_bridge_apis.length +
290
+ analysis.electron.ipc.length +
291
+ analysis.electron.sender_validations.length +
292
+ analysis.electron.utility_processes.length +
293
+ analysis.electron.native_addon_bindings.length;
294
+ const rangeForOffsets = (text, start, end) => ({
295
+ start: pointForOffset(text, start),
296
+ end: pointForOffset(text, end),
297
+ });
298
+ const pointForOffset = (text, offset) => {
299
+ const lines = text.slice(0, offset).split("\n");
300
+ return { line: lines.length, column: lines.at(-1)?.length ?? 0 };
301
+ };
302
+ const resolveSourceName = (root, source) => `${root}${root !== "" && !root.endsWith("/") ? "/" : ""}${source}`.slice(0, 4_096);
303
+ const boundedString = (value) => typeof value === "string" && value.length > 0 ? value.slice(0, 4_096) : null;
304
+ const sha256 = (value) => createHash("sha256").update(value).digest("hex");
305
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);