@oneuptime/common 12.0.22 → 12.0.24

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 (345) hide show
  1. package/Models/DatabaseModels/DetectionRule.ts +55 -0
  2. package/Models/DatabaseModels/Index.ts +2 -0
  3. package/Models/DatabaseModels/NetworkDevice.ts +44 -0
  4. package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +584 -0
  5. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +105 -0
  6. package/Models/DatabaseModels/Project.ts +68 -0
  7. package/Models/DatabaseModels/User.ts +68 -0
  8. package/Server/API/TelemetryAPI.ts +29 -0
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/1789100000000-AddNetworkDeviceAutoImportRule.ts +60 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/1789200000000-AddSysObjectIdPatternToAutoImportRule.ts +26 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1789300000000-AddAutoApplyVendorHealthTemplate.ts +26 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.ts +28 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.ts +49 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.ts +33 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  16. package/Server/Middleware/GzipRequestBody.ts +311 -0
  17. package/Server/Middleware/MultipartFormData.ts +87 -3
  18. package/Server/Services/DetectionRuleService.ts +73 -6
  19. package/Server/Services/Index.ts +207 -0
  20. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +917 -0
  21. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +181 -0
  22. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +59 -0
  23. package/Server/Services/NetworkDeviceService.ts +148 -0
  24. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
  25. package/Server/Services/OnCallDutyPolicyFeedService.ts +1 -1
  26. package/Server/Services/ProjectService.ts +29 -19
  27. package/Server/Services/SecurityEventService.ts +90 -13
  28. package/Server/Services/StatusPageResourceService.ts +223 -0
  29. package/Server/Services/TelemetryAttributeService.ts +17 -0
  30. package/Server/Services/UserService.ts +4 -6
  31. package/Server/Types/Markdown.ts +161 -67
  32. package/Server/Utils/AI/Toolbox/OnCallTools.ts +12 -4
  33. package/Server/Utils/AnalyticsDatabase/Statement.ts +13 -1
  34. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +297 -6
  35. package/Server/Utils/Attribution.ts +4 -0
  36. package/Server/Utils/Marketing/MarketingEventUtil.ts +45 -7
  37. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +39 -1
  38. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +55 -3
  39. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +21 -0
  40. package/Server/Utils/StartServer.ts +12 -32
  41. package/Server/Utils/Telemetry/LlmCostBudgetEvaluator.ts +101 -4
  42. package/Server/Utils/Telemetry/LlmMetricSpend.ts +130 -0
  43. package/Server/Views/Partials/AnalyticsConsent.ejs +159 -102
  44. package/Server/Views/Partials/Head.ejs +2 -1
  45. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +776 -38
  46. package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +359 -0
  47. package/Tests/App/Dashboard/CorrelateGraph.test.tsx +865 -0
  48. package/Tests/App/Dashboard/CorrelationGraph.test.ts +346 -0
  49. package/Tests/App/Dashboard/CriteriaFilterConditionDropdown.test.tsx +256 -0
  50. package/Tests/App/Dashboard/CriteriaFilterDefaults.test.ts +738 -0
  51. package/Tests/App/Dashboard/CriteriaFilterMonitorTypeChange.test.ts +1122 -0
  52. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +283 -0
  53. package/Tests/App/Dashboard/ExternalStatusPageCriteriaFilter.test.ts +407 -0
  54. package/Tests/App/Dashboard/MetricSeriesInvestigateMenu.test.tsx +5 -14
  55. package/Tests/App/Dashboard/MonitorCriteriaActionToggles.test.tsx +426 -0
  56. package/Tests/App/Dashboard/MonitorStepsCriteriaAlignmentWiring.test.tsx +352 -0
  57. package/Tests/App/Dashboard/OnCallLayerCardOverrides.test.tsx +278 -0
  58. package/Tests/App/Dashboard/OnCallLayerShiftPreviewOverrides.test.ts +237 -0
  59. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +2 -2
  60. package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +460 -0
  61. package/Tests/App/Dashboard/SecurityEventAttributeUtil.test.ts +171 -0
  62. package/Tests/App/Dashboard/SecurityEventCorrelation.test.ts +857 -0
  63. package/Tests/App/Dashboard/SecurityEventDetailObservables.test.tsx +194 -0
  64. package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +124 -0
  65. package/Tests/App/Dashboard/SecurityEventsMonitorStepForm.test.tsx +79 -19
  66. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +382 -0
  67. package/Tests/App/StatusPage/BulkAddStatusPageMonitors.test.ts +216 -0
  68. package/Tests/App/StatusPage/BulkAddStatusPageMonitorsModal.test.tsx +590 -11
  69. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +757 -0
  70. package/Tests/Models/DiscoveryScanNameColumn.test.ts +293 -0
  71. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +564 -0
  72. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +120 -4
  73. package/Tests/Server/Middleware/GzipRequestBody.test.ts +725 -0
  74. package/Tests/Server/Middleware/MultipartFormData.test.ts +298 -0
  75. package/Tests/Server/Services/AddDetectionRuleDistinctCountColumnsMigration.test.ts +311 -0
  76. package/Tests/Server/Services/AutoImportScanCredentialSelect.test.ts +205 -0
  77. package/Tests/Server/Services/DetectionRuleService.test.ts +134 -2
  78. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +7 -1
  79. package/Tests/Server/Services/FeedRetentionConsistency.test.ts +131 -0
  80. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +933 -0
  81. package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +194 -0
  82. package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +800 -0
  83. package/Tests/Server/Services/OnCallScheduleAttachRosterRefresh.test.ts +244 -0
  84. package/Tests/Server/Services/SecurityEventService.test.ts +376 -0
  85. package/Tests/Server/Services/StatusPageResourceDuplicates.test.ts +703 -0
  86. package/Tests/Server/Services/TelemetryAttributeServiceSecurityEvent.test.ts +256 -0
  87. package/Tests/Server/Types/Workflow/Components/ComponentRegistryParity.test.ts +417 -0
  88. package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorWhereOperators.test.ts +677 -0
  89. package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +43 -0
  90. package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +15 -11
  91. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +97 -1
  92. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +369 -8
  93. package/Tests/Server/Utils/SecurityEvent/SigmaClickhouseCompiler.test.ts +35 -0
  94. package/Tests/Server/Utils/Telemetry/LlmCostBudgetEvaluator.test.ts +368 -4
  95. package/Tests/Server/Utils/Telemetry/LlmMetricSpend.test.ts +245 -0
  96. package/Tests/Server/Views/AnalyticsConsentPartial.test.ts +48 -5
  97. package/Tests/Types/Code/YamlSyntax.test.ts +396 -0
  98. package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +957 -0
  99. package/Tests/Types/Monitor/MonitorCriteriaActionValidation.test.ts +598 -0
  100. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +49 -0
  101. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +6 -6
  102. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +4 -4
  103. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +4 -3
  104. package/Tests/Types/Telemetry/LlmMetricConventions.test.ts +193 -0
  105. package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +0 -12
  106. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +1 -17
  107. package/Tests/UI/Components/CodeEditor.test.tsx +474 -10
  108. package/Tests/UI/Components/Detail/YamlField.test.tsx +105 -0
  109. package/Tests/UI/Components/EntityDropdownLabelsBulkAdd.test.tsx +319 -0
  110. package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +231 -0
  111. package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +1 -0
  112. package/Tests/UI/Components/Forms/ValidationYAML.test.ts +234 -0
  113. package/Tests/UI/Components/ModelTable/AttributeColumns.test.tsx +573 -0
  114. package/Tests/UI/Components/ModelTable/BaseModelTableAttributeColumns.test.tsx +824 -0
  115. package/Tests/UI/Components/ModelTable/ColumnCustomizationModalAddableColumns.test.tsx +707 -0
  116. package/Tests/UI/Components/SideOver.test.tsx +1 -1
  117. package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +294 -0
  118. package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +436 -0
  119. package/Tests/UI/Components/TableBulkCsvExport.test.tsx +6 -2
  120. package/Tests/UI/Components/Toggle.test.tsx +25 -0
  121. package/Tests/UI/Components/YamlEditor.test.tsx +847 -0
  122. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +252 -0
  123. package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +516 -0
  124. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +272 -0
  125. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +221 -0
  126. package/Tests/Utils/NetworkDiscovery/ScanNameUtil.test.ts +312 -0
  127. package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +164 -0
  128. package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +468 -0
  129. package/Tests/Utils/Telemetry/LlmMetricQuery.test.ts +472 -0
  130. package/Types/Code/YamlSyntax.ts +396 -0
  131. package/Types/Exception/ExceptionCode.ts +1 -0
  132. package/Types/Exception/PayloadTooLargeException.ts +8 -0
  133. package/Types/Marketing/Attribution.ts +10 -0
  134. package/Types/Marketing/MarketingEvent.ts +4 -0
  135. package/Types/Monitor/MonitorCriteriaInstance.ts +116 -56
  136. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +2 -1
  137. package/Types/NetworkAutomation/RuleRunResult.ts +84 -0
  138. package/Types/Permission.ts +47 -0
  139. package/Types/SecurityEvent/DetectionFindingConstants.ts +11 -0
  140. package/Types/Telemetry/LlmMetricConventions.ts +124 -0
  141. package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +3 -0
  142. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +10 -1
  143. package/UI/Components/CodeEditor/CodeEditor.tsx +241 -79
  144. package/UI/Components/CodeEditor/YamlEditor.tsx +369 -0
  145. package/UI/Components/Detail/Detail.tsx +10 -0
  146. package/UI/Components/EntityDropdown/EntityDropdown.tsx +33 -0
  147. package/UI/Components/Forms/Fields/FormField.tsx +31 -0
  148. package/UI/Components/Forms/Types/Field.ts +8 -0
  149. package/UI/Components/Forms/Types/FormFieldSchemaType.ts +1 -0
  150. package/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.ts +2 -0
  151. package/UI/Components/Forms/Validation.ts +46 -0
  152. package/UI/Components/Input/Input.tsx +3 -0
  153. package/UI/Components/ModelTable/AttributeColumns.tsx +321 -0
  154. package/UI/Components/ModelTable/BaseModelTable.tsx +263 -14
  155. package/UI/Components/ModelTable/Column.ts +8 -0
  156. package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +310 -0
  157. package/UI/Components/ModelTable/ColumnPreference.ts +13 -1
  158. package/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.tsx +2 -2
  159. package/UI/Components/SideOver/SideOver.tsx +5 -5
  160. package/UI/Components/StatusPage/ResourceGrid.tsx +82 -2
  161. package/UI/Components/StatusPage/ResourceList.tsx +197 -38
  162. package/UI/Components/Toggle/Toggle.tsx +9 -1
  163. package/UI/Components/Types/FieldType.ts +1 -0
  164. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +73 -1
  165. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +257 -0
  166. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +183 -0
  167. package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +95 -0
  168. package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +66 -0
  169. package/Utils/NetworkDiscovery/ScanNameUtil.ts +181 -0
  170. package/Utils/NetworkDiscovery/ScanTargetUtil.ts +82 -0
  171. package/Utils/StatusPage/ResourceExplorer.ts +258 -0
  172. package/Utils/Telemetry/LlmMetricQuery.ts +204 -0
  173. package/build/dist/Models/DatabaseModels/DetectionRule.js +57 -0
  174. package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
  175. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  176. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  177. package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
  178. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  179. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +609 -0
  180. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -0
  181. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +97 -0
  182. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  183. package/build/dist/Models/DatabaseModels/Project.js +76 -0
  184. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  185. package/build/dist/Models/DatabaseModels/User.js +76 -0
  186. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  187. package/build/dist/Server/API/TelemetryAPI.js +17 -0
  188. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  189. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789100000000-AddNetworkDeviceAutoImportRule.js +35 -0
  190. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789100000000-AddNetworkDeviceAutoImportRule.js.map +1 -0
  191. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789200000000-AddSysObjectIdPatternToAutoImportRule.js +19 -0
  192. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789200000000-AddSysObjectIdPatternToAutoImportRule.js.map +1 -0
  193. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789300000000-AddAutoApplyVendorHealthTemplate.js +19 -0
  194. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789300000000-AddAutoApplyVendorHealthTemplate.js.map +1 -0
  195. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js +21 -0
  196. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js.map +1 -0
  197. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js +42 -0
  198. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js.map +1 -0
  199. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js +22 -0
  200. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js.map +1 -0
  201. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  202. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  203. package/build/dist/Server/Middleware/GzipRequestBody.js +224 -0
  204. package/build/dist/Server/Middleware/GzipRequestBody.js.map +1 -0
  205. package/build/dist/Server/Middleware/MultipartFormData.js +71 -2
  206. package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
  207. package/build/dist/Server/Services/DetectionRuleService.js +49 -4
  208. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
  209. package/build/dist/Server/Services/Index.js +206 -0
  210. package/build/dist/Server/Services/Index.js.map +1 -1
  211. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +711 -0
  212. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -0
  213. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +155 -0
  214. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -0
  215. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +50 -0
  216. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
  217. package/build/dist/Server/Services/NetworkDeviceService.js +124 -0
  218. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  219. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +68 -13
  220. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  221. package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js +1 -1
  222. package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js.map +1 -1
  223. package/build/dist/Server/Services/ProjectService.js +25 -45
  224. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  225. package/build/dist/Server/Services/SecurityEventService.js +57 -5
  226. package/build/dist/Server/Services/SecurityEventService.js.map +1 -1
  227. package/build/dist/Server/Services/StatusPageResourceService.js +140 -0
  228. package/build/dist/Server/Services/StatusPageResourceService.js.map +1 -1
  229. package/build/dist/Server/Services/TelemetryAttributeService.js +17 -0
  230. package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
  231. package/build/dist/Server/Services/UserService.js +2 -12
  232. package/build/dist/Server/Services/UserService.js.map +1 -1
  233. package/build/dist/Server/Types/Markdown.js +147 -61
  234. package/build/dist/Server/Types/Markdown.js.map +1 -1
  235. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +12 -4
  236. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -1
  237. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +12 -1
  238. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  239. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +246 -9
  240. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  241. package/build/dist/Server/Utils/Attribution.js.map +1 -1
  242. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +27 -7
  243. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -1
  244. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +26 -0
  245. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  246. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +42 -7
  247. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
  248. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +18 -0
  249. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
  250. package/build/dist/Server/Utils/StartServer.js +12 -21
  251. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  252. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js +76 -5
  253. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js.map +1 -1
  254. package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js +102 -0
  255. package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js.map +1 -0
  256. package/build/dist/Types/Code/YamlSyntax.js +212 -0
  257. package/build/dist/Types/Code/YamlSyntax.js.map +1 -0
  258. package/build/dist/Types/Exception/ExceptionCode.js +1 -0
  259. package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
  260. package/build/dist/Types/Exception/PayloadTooLargeException.js +8 -0
  261. package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -0
  262. package/build/dist/Types/Marketing/Attribution.js +10 -0
  263. package/build/dist/Types/Marketing/Attribution.js.map +1 -1
  264. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +112 -51
  265. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  266. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +2 -1
  267. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
  268. package/build/dist/Types/NetworkAutomation/RuleRunResult.js +24 -0
  269. package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -1
  270. package/build/dist/Types/Permission.js +41 -0
  271. package/build/dist/Types/Permission.js.map +1 -1
  272. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +9 -0
  273. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
  274. package/build/dist/Types/Telemetry/LlmMetricConventions.js +98 -0
  275. package/build/dist/Types/Telemetry/LlmMetricConventions.js.map +1 -0
  276. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
  277. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
  278. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +5 -2
  279. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  280. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +206 -76
  281. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  282. package/build/dist/UI/Components/CodeEditor/YamlEditor.js +201 -0
  283. package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -0
  284. package/build/dist/UI/Components/Detail/Detail.js +9 -0
  285. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  286. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +16 -1
  287. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  288. package/build/dist/UI/Components/Forms/Fields/FormField.js +14 -1
  289. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  290. package/build/dist/UI/Components/Forms/Types/Field.js.map +1 -1
  291. package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js +1 -0
  292. package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js.map +1 -1
  293. package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js +2 -0
  294. package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js.map +1 -1
  295. package/build/dist/UI/Components/Forms/Validation.js +27 -0
  296. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  297. package/build/dist/UI/Components/Input/Input.js +1 -1
  298. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  299. package/build/dist/UI/Components/ModelTable/AttributeColumns.js +159 -0
  300. package/build/dist/UI/Components/ModelTable/AttributeColumns.js.map +1 -0
  301. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +179 -17
  302. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  303. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +133 -2
  304. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
  305. package/build/dist/UI/Components/ModelTable/ColumnPreference.js +7 -1
  306. package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -1
  307. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.js +2 -2
  308. package/build/dist/UI/Components/SideOver/SideOver.js +5 -5
  309. package/build/dist/UI/Components/StatusPage/ResourceGrid.js +28 -2
  310. package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
  311. package/build/dist/UI/Components/StatusPage/ResourceList.js +87 -20
  312. package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
  313. package/build/dist/UI/Components/Toggle/Toggle.js +9 -1
  314. package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
  315. package/build/dist/UI/Components/Types/FieldType.js +1 -0
  316. package/build/dist/UI/Components/Types/FieldType.js.map +1 -1
  317. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +37 -1
  318. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
  319. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +149 -0
  320. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -0
  321. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +121 -0
  322. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -0
  323. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +75 -0
  324. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -0
  325. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +59 -0
  326. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -0
  327. package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js +120 -0
  328. package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js.map +1 -0
  329. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +60 -0
  330. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -1
  331. package/build/dist/Utils/StatusPage/ResourceExplorer.js +171 -0
  332. package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -1
  333. package/build/dist/Utils/Telemetry/LlmMetricQuery.js +119 -0
  334. package/build/dist/Utils/Telemetry/LlmMetricQuery.js.map +1 -0
  335. package/jest.config.json +2 -0
  336. package/package.json +1 -1
  337. package/tsconfig.json +2 -1
  338. package/Tests/UI/Components/Toast.test.tsx +0 -197
  339. package/Tests/UI/Components/ToastStacking.test.tsx +0 -198
  340. package/UI/Components/Toast/Toast.tsx +0 -189
  341. package/UI/Components/Toast/ToastInit.tsx +0 -110
  342. package/build/dist/UI/Components/Toast/Toast.js +0 -123
  343. package/build/dist/UI/Components/Toast/Toast.js.map +0 -1
  344. package/build/dist/UI/Components/Toast/ToastInit.js +0 -53
  345. package/build/dist/UI/Components/Toast/ToastInit.js.map +0 -1
@@ -0,0 +1,857 @@
1
+ import { describe, expect, test } from "@jest/globals";
2
+ import EqualTo from "../../../Types/BaseDatabase/EqualTo";
3
+ import InBetween from "../../../Types/BaseDatabase/InBetween";
4
+ import Includes from "../../../Types/BaseDatabase/Includes";
5
+ import IncludesAll from "../../../Types/BaseDatabase/IncludesAll";
6
+ import IncludesNone from "../../../Types/BaseDatabase/IncludesNone";
7
+ import NotContains from "../../../Types/BaseDatabase/NotContains";
8
+ import NotEqual from "../../../Types/BaseDatabase/NotEqual";
9
+ import Search from "../../../Types/BaseDatabase/Search";
10
+ import StartsWith from "../../../Types/BaseDatabase/StartsWith";
11
+ import EndsWith from "../../../Types/BaseDatabase/EndsWith";
12
+ import ObjectID from "../../../Types/ObjectID";
13
+ import OcsfSeverity from "../../../Types/SecurityEvent/OcsfSeverity";
14
+ import {
15
+ CompiledCorrelationQueries,
16
+ CorrelationCondition,
17
+ CorrelationFieldDefinition,
18
+ CorrelationFieldDefinitions,
19
+ CorrelationFieldKey,
20
+ CorrelationFilter,
21
+ CorrelationOperator,
22
+ CorrelationOperatorLabels,
23
+ CorrelationQueryOptions,
24
+ compileCorrelationFilter,
25
+ describeCorrelationCondition,
26
+ describeCorrelationFilter,
27
+ getCorrelationFieldDefinition,
28
+ getEqualityObservables,
29
+ parseCorrelationFilter,
30
+ serializeCorrelationFilter,
31
+ } from "../../../../App/FeatureSet/Dashboard/src/Utils/SecurityEventCorrelation";
32
+
33
+ /*
34
+ * The correlation filter compiler is the contract between the Correlate
35
+ * query-builder UI (issue #3395) and the flat analytics query API: AND
36
+ * chains must land in ONE query (with same-column conditions merged into an
37
+ * equivalent single operator or rejected with a friendly error — never
38
+ * silently wrong), OR chains must fan out into one query per condition with
39
+ * same-field equalities collapsed into a single Includes. These tests pin
40
+ * every compilation rule, the URL round-trip, and the tolerance of the
41
+ * parser against malformed input.
42
+ */
43
+
44
+ const PROJECT_ID: ObjectID = new ObjectID(
45
+ "11111111-1111-4111-8111-111111111111",
46
+ );
47
+ const START_DATE: Date = new Date("2026-08-24T00:00:00.000Z");
48
+ const END_DATE: Date = new Date("2026-08-25T00:00:00.000Z");
49
+
50
+ const options: CorrelationQueryOptions = {
51
+ projectId: PROJECT_ID,
52
+ startDate: START_DATE,
53
+ endDate: END_DATE,
54
+ };
55
+
56
+ function condition(
57
+ field: CorrelationFieldKey,
58
+ operator: CorrelationOperator,
59
+ value: string,
60
+ ): CorrelationCondition {
61
+ return { field, operator, value };
62
+ }
63
+
64
+ function compile(
65
+ conditions: Array<CorrelationCondition>,
66
+ connector: "and" | "or",
67
+ ): CompiledCorrelationQueries {
68
+ return compileCorrelationFilter({ conditions, connector }, options);
69
+ }
70
+
71
+ type QueryRecord = Record<string, unknown>;
72
+
73
+ function expectBaseQuery(query: QueryRecord): void {
74
+ expect(query["projectId"]).toBe(PROJECT_ID);
75
+ expect(query["time"]).toBeInstanceOf(InBetween);
76
+ expect((query["time"] as InBetween<Date>).startValue).toBe(START_DATE);
77
+ expect((query["time"] as InBetween<Date>).endValue).toBe(END_DATE);
78
+ }
79
+
80
+ describe("field catalog", () => {
81
+ test("every field offers at least one operator, and only labeled operators", () => {
82
+ for (const definition of CorrelationFieldDefinitions) {
83
+ expect(definition.operators.length).toBeGreaterThan(0);
84
+ for (const operator of definition.operators) {
85
+ expect(CorrelationOperatorLabels[operator]).toBeTruthy();
86
+ }
87
+ }
88
+ });
89
+
90
+ test("the observable field targets the observables array column", () => {
91
+ const definition: CorrelationFieldDefinition =
92
+ getCorrelationFieldDefinition(CorrelationFieldKey.Observable);
93
+ expect(definition.columnKey).toBe("observables");
94
+ expect(definition.isArrayColumn).toBe(true);
95
+ });
96
+
97
+ test("severity offers a fixed value vocabulary", () => {
98
+ const definition: CorrelationFieldDefinition =
99
+ getCorrelationFieldDefinition(CorrelationFieldKey.Severity);
100
+ expect(definition.valueOptions).toEqual(Object.values(OcsfSeverity));
101
+ expect(definition.operators).toEqual([
102
+ CorrelationOperator.Equals,
103
+ CorrelationOperator.NotEquals,
104
+ ]);
105
+ });
106
+
107
+ test("event class suggests the curated OCSF names but stays free-text", () => {
108
+ const definition: CorrelationFieldDefinition =
109
+ getCorrelationFieldDefinition(CorrelationFieldKey.EventClass);
110
+ expect(definition.valueOptions).toBeUndefined();
111
+ expect(definition.valueSuggestions).toContain("Authentication");
112
+ expect(definition.valueSuggestions).toContain("Detection Finding");
113
+ });
114
+
115
+ test("getCorrelationFieldDefinition throws for an unknown field", () => {
116
+ expect(() => {
117
+ return getCorrelationFieldDefinition("nope" as CorrelationFieldKey);
118
+ }).toThrow("Unknown correlation field: nope");
119
+ });
120
+ });
121
+
122
+ describe("AND compilation — single conditions", () => {
123
+ test.each<[CorrelationOperator, (value: unknown) => void]>([
124
+ [
125
+ CorrelationOperator.Equals,
126
+ (value: unknown): void => {
127
+ expect(value).toBeInstanceOf(Includes);
128
+ expect((value as Includes).values).toEqual(["wb-ubuntu-03"]);
129
+ },
130
+ ],
131
+ [
132
+ CorrelationOperator.NotEquals,
133
+ (value: unknown): void => {
134
+ expect(value).toBeInstanceOf(IncludesNone);
135
+ expect((value as IncludesNone).values).toEqual(["wb-ubuntu-03"]);
136
+ },
137
+ ],
138
+ [
139
+ CorrelationOperator.Contains,
140
+ (value: unknown): void => {
141
+ expect(value).toBeInstanceOf(Search);
142
+ expect((value as Search<string>).toString()).toBe("wb-ubuntu-03");
143
+ },
144
+ ],
145
+ [
146
+ CorrelationOperator.NotContains,
147
+ (value: unknown): void => {
148
+ expect(value).toBeInstanceOf(NotContains);
149
+ },
150
+ ],
151
+ [
152
+ CorrelationOperator.StartsWith,
153
+ (value: unknown): void => {
154
+ expect(value).toBeInstanceOf(StartsWith);
155
+ },
156
+ ],
157
+ [
158
+ CorrelationOperator.EndsWith,
159
+ (value: unknown): void => {
160
+ expect(value).toBeInstanceOf(EndsWith);
161
+ },
162
+ ],
163
+ ])(
164
+ "observable %s compiles onto the observables column",
165
+ (operator: CorrelationOperator, assertValue: (value: unknown) => void) => {
166
+ const compiled: CompiledCorrelationQueries = compile(
167
+ [condition(CorrelationFieldKey.Observable, operator, "wb-ubuntu-03")],
168
+ "and",
169
+ );
170
+ expect(compiled.error).toBeNull();
171
+ expect(compiled.queries).toHaveLength(1);
172
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
173
+ expectBaseQuery(query);
174
+ assertValue(query["observables"]);
175
+ },
176
+ );
177
+
178
+ test("scalar equals compiles to a bare value (the fast equality path)", () => {
179
+ const compiled: CompiledCorrelationQueries = compile(
180
+ [
181
+ condition(
182
+ CorrelationFieldKey.PrincipalHost,
183
+ CorrelationOperator.Equals,
184
+ "wb-ubuntu-03",
185
+ ),
186
+ ],
187
+ "and",
188
+ );
189
+ expect(compiled.error).toBeNull();
190
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
191
+ expect(query["principalHost"]).toBe("wb-ubuntu-03");
192
+ });
193
+
194
+ test("scalar not-equals compiles to NotEqual", () => {
195
+ const compiled: CompiledCorrelationQueries = compile(
196
+ [
197
+ condition(
198
+ CorrelationFieldKey.PrincipalUser,
199
+ CorrelationOperator.NotEquals,
200
+ "baduser1",
201
+ ),
202
+ ],
203
+ "and",
204
+ );
205
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
206
+ expect(query["principalUser"]).toBeInstanceOf(NotEqual);
207
+ expect((query["principalUser"] as NotEqual<string>).value).toBe("baduser1");
208
+ });
209
+
210
+ test("scalar contains compiles to Search", () => {
211
+ const compiled: CompiledCorrelationQueries = compile(
212
+ [
213
+ condition(
214
+ CorrelationFieldKey.Message,
215
+ CorrelationOperator.Contains,
216
+ "failed password",
217
+ ),
218
+ ],
219
+ "and",
220
+ );
221
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
222
+ expect(query["message"]).toBeInstanceOf(Search);
223
+ });
224
+ });
225
+
226
+ describe("AND compilation — the issue #3395 shapes", () => {
227
+ test("IP = X AND Hostname = Y (different fields) lands in one query", () => {
228
+ const compiled: CompiledCorrelationQueries = compile(
229
+ [
230
+ condition(
231
+ CorrelationFieldKey.PrincipalIp,
232
+ CorrelationOperator.Equals,
233
+ "192.168.1.20",
234
+ ),
235
+ condition(
236
+ CorrelationFieldKey.PrincipalHost,
237
+ CorrelationOperator.Equals,
238
+ "wb-ubuntu-03",
239
+ ),
240
+ ],
241
+ "and",
242
+ );
243
+ expect(compiled.error).toBeNull();
244
+ expect(compiled.queries).toHaveLength(1);
245
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
246
+ expectBaseQuery(query);
247
+ expect(query["principalIp"]).toBe("192.168.1.20");
248
+ expect(query["principalHost"]).toBe("wb-ubuntu-03");
249
+ });
250
+
251
+ test("Hostname = X AND User != Y mixes equality and exclusion across fields", () => {
252
+ const compiled: CompiledCorrelationQueries = compile(
253
+ [
254
+ condition(
255
+ CorrelationFieldKey.PrincipalHost,
256
+ CorrelationOperator.Equals,
257
+ "wb-ubuntu-03",
258
+ ),
259
+ condition(
260
+ CorrelationFieldKey.PrincipalUser,
261
+ CorrelationOperator.NotEquals,
262
+ "baduser1",
263
+ ),
264
+ ],
265
+ "and",
266
+ );
267
+ expect(compiled.error).toBeNull();
268
+ expect(compiled.queries).toHaveLength(1);
269
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
270
+ expect(query["principalHost"]).toBe("wb-ubuntu-03");
271
+ expect(query["principalUser"]).toBeInstanceOf(NotEqual);
272
+ });
273
+
274
+ test("Observable = X AND Observable = Y merges into IncludesAll (hasAll)", () => {
275
+ const compiled: CompiledCorrelationQueries = compile(
276
+ [
277
+ condition(
278
+ CorrelationFieldKey.Observable,
279
+ CorrelationOperator.Equals,
280
+ "wb-ubuntu-03",
281
+ ),
282
+ condition(
283
+ CorrelationFieldKey.Observable,
284
+ CorrelationOperator.Equals,
285
+ "192.168.1.20",
286
+ ),
287
+ ],
288
+ "and",
289
+ );
290
+ expect(compiled.error).toBeNull();
291
+ expect(compiled.queries).toHaveLength(1);
292
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
293
+ expect(query["observables"]).toBeInstanceOf(IncludesAll);
294
+ expect((query["observables"] as IncludesAll).values).toEqual([
295
+ "wb-ubuntu-03",
296
+ "192.168.1.20",
297
+ ]);
298
+ });
299
+
300
+ test("Observable != X AND Observable != Y merges into IncludesNone", () => {
301
+ const compiled: CompiledCorrelationQueries = compile(
302
+ [
303
+ condition(
304
+ CorrelationFieldKey.Observable,
305
+ CorrelationOperator.NotEquals,
306
+ "known-scanner",
307
+ ),
308
+ condition(
309
+ CorrelationFieldKey.Observable,
310
+ CorrelationOperator.NotEquals,
311
+ "10.0.0.99",
312
+ ),
313
+ ],
314
+ "and",
315
+ );
316
+ expect(compiled.error).toBeNull();
317
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
318
+ expect(query["observables"]).toBeInstanceOf(IncludesNone);
319
+ expect((query["observables"] as IncludesNone).values).toEqual([
320
+ "known-scanner",
321
+ "10.0.0.99",
322
+ ]);
323
+ });
324
+
325
+ test("scalar != X AND != Y merges into IncludesNone (NOT IN)", () => {
326
+ const compiled: CompiledCorrelationQueries = compile(
327
+ [
328
+ condition(
329
+ CorrelationFieldKey.PrincipalUser,
330
+ CorrelationOperator.NotEquals,
331
+ "baduser1",
332
+ ),
333
+ condition(
334
+ CorrelationFieldKey.PrincipalUser,
335
+ CorrelationOperator.NotEquals,
336
+ "baduser2",
337
+ ),
338
+ ],
339
+ "and",
340
+ );
341
+ expect(compiled.error).toBeNull();
342
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
343
+ expect(query["principalUser"]).toBeInstanceOf(IncludesNone);
344
+ expect((query["principalUser"] as IncludesNone).values).toEqual([
345
+ "baduser1",
346
+ "baduser2",
347
+ ]);
348
+ });
349
+ });
350
+
351
+ describe("AND compilation — impossible or inexpressible chains fail with a friendly error", () => {
352
+ test("two different equalities on a scalar can never match", () => {
353
+ const compiled: CompiledCorrelationQueries = compile(
354
+ [
355
+ condition(
356
+ CorrelationFieldKey.PrincipalHost,
357
+ CorrelationOperator.Equals,
358
+ "host-a",
359
+ ),
360
+ condition(
361
+ CorrelationFieldKey.PrincipalHost,
362
+ CorrelationOperator.Equals,
363
+ "host-b",
364
+ ),
365
+ ],
366
+ "and",
367
+ );
368
+ expect(compiled.queries).toHaveLength(0);
369
+ expect(compiled.error).toContain("can never match");
370
+ expect(compiled.error).toContain("Principal Host");
371
+ });
372
+
373
+ test("Observable = X AND Observable != Y compiles to an operator ARRAY (hasAll + NOT hasAny)", () => {
374
+ /*
375
+ * Two predicates on one column don't fit the flat query map's single
376
+ * slot — the compiler emits an array of operators under the key, which
377
+ * the statement generator ANDs. This is the graph's "Exclude" pivot.
378
+ */
379
+ const compiled: CompiledCorrelationQueries = compile(
380
+ [
381
+ condition(
382
+ CorrelationFieldKey.Observable,
383
+ CorrelationOperator.Equals,
384
+ "wb-ubuntu-03",
385
+ ),
386
+ condition(
387
+ CorrelationFieldKey.Observable,
388
+ CorrelationOperator.NotEquals,
389
+ "baduser1",
390
+ ),
391
+ ],
392
+ "and",
393
+ );
394
+ expect(compiled.error).toBeNull();
395
+ expect(compiled.queries).toHaveLength(1);
396
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
397
+ const operators: Array<unknown> = query["observables"] as Array<unknown>;
398
+ expect(Array.isArray(operators)).toBe(true);
399
+ expect(operators).toHaveLength(2);
400
+ expect(operators[0]).toBeInstanceOf(Includes);
401
+ expect((operators[0] as Includes).values).toEqual(["wb-ubuntu-03"]);
402
+ expect(operators[1]).toBeInstanceOf(IncludesNone);
403
+ expect((operators[1] as IncludesNone).values).toEqual(["baduser1"]);
404
+ });
405
+
406
+ test("two equals AND one not-equals on observables → [IncludesAll, IncludesNone]", () => {
407
+ const compiled: CompiledCorrelationQueries = compile(
408
+ [
409
+ condition(
410
+ CorrelationFieldKey.Observable,
411
+ CorrelationOperator.Equals,
412
+ "wb-ubuntu-03",
413
+ ),
414
+ condition(
415
+ CorrelationFieldKey.Observable,
416
+ CorrelationOperator.Equals,
417
+ "192.168.1.20",
418
+ ),
419
+ condition(
420
+ CorrelationFieldKey.Observable,
421
+ CorrelationOperator.NotEquals,
422
+ "baduser1",
423
+ ),
424
+ ],
425
+ "and",
426
+ );
427
+ expect(compiled.error).toBeNull();
428
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
429
+ const operators: Array<unknown> = query["observables"] as Array<unknown>;
430
+ expect(operators).toHaveLength(2);
431
+ expect(operators[0]).toBeInstanceOf(IncludesAll);
432
+ expect((operators[0] as IncludesAll).values).toEqual([
433
+ "wb-ubuntu-03",
434
+ "192.168.1.20",
435
+ ]);
436
+ expect(operators[1]).toBeInstanceOf(IncludesNone);
437
+ });
438
+
439
+ test("two contains conditions on the same field compile to two Search operators ANDed", () => {
440
+ const compiled: CompiledCorrelationQueries = compile(
441
+ [
442
+ condition(
443
+ CorrelationFieldKey.Message,
444
+ CorrelationOperator.Contains,
445
+ "failed",
446
+ ),
447
+ condition(
448
+ CorrelationFieldKey.Message,
449
+ CorrelationOperator.Contains,
450
+ "password",
451
+ ),
452
+ ],
453
+ "and",
454
+ );
455
+ expect(compiled.error).toBeNull();
456
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
457
+ const operators: Array<unknown> = query["message"] as Array<unknown>;
458
+ expect(operators).toHaveLength(2);
459
+ expect(operators[0]).toBeInstanceOf(Search);
460
+ expect(operators[1]).toBeInstanceOf(Search);
461
+ });
462
+
463
+ test("scalar equals AND not-equals on the same field → [EqualTo, NotEqual] array", () => {
464
+ const compiled: CompiledCorrelationQueries = compile(
465
+ [
466
+ condition(
467
+ CorrelationFieldKey.PrincipalUser,
468
+ CorrelationOperator.Equals,
469
+ "alice",
470
+ ),
471
+ condition(
472
+ CorrelationFieldKey.PrincipalUser,
473
+ CorrelationOperator.NotEquals,
474
+ "bob",
475
+ ),
476
+ ],
477
+ "and",
478
+ );
479
+ expect(compiled.error).toBeNull();
480
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
481
+ const operators: Array<unknown> = query["principalUser"] as Array<unknown>;
482
+ expect(operators).toHaveLength(2);
483
+ expect(operators[0]).toBeInstanceOf(EqualTo);
484
+ expect((operators[0] as EqualTo<string>).value).toBe("alice");
485
+ expect(operators[1]).toBeInstanceOf(NotEqual);
486
+ expect((operators[1] as NotEqual<string>).value).toBe("bob");
487
+ });
488
+
489
+ test("an empty condition value is rejected with the field named", () => {
490
+ const compiled: CompiledCorrelationQueries = compile(
491
+ [
492
+ condition(
493
+ CorrelationFieldKey.Observable,
494
+ CorrelationOperator.Equals,
495
+ " ",
496
+ ),
497
+ ],
498
+ "and",
499
+ );
500
+ expect(compiled.queries).toHaveLength(0);
501
+ expect(compiled.error).toContain("Observable");
502
+ expect(compiled.error).toContain("needs a value");
503
+ });
504
+ });
505
+
506
+ describe("AND compilation — normalization", () => {
507
+ test("values are trimmed", () => {
508
+ const compiled: CompiledCorrelationQueries = compile(
509
+ [
510
+ condition(
511
+ CorrelationFieldKey.PrincipalHost,
512
+ CorrelationOperator.Equals,
513
+ " wb-ubuntu-03 ",
514
+ ),
515
+ ],
516
+ "and",
517
+ );
518
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
519
+ expect(query["principalHost"]).toBe("wb-ubuntu-03");
520
+ });
521
+
522
+ test("identical duplicate rows collapse instead of erroring", () => {
523
+ const compiled: CompiledCorrelationQueries = compile(
524
+ [
525
+ condition(
526
+ CorrelationFieldKey.PrincipalHost,
527
+ CorrelationOperator.Equals,
528
+ "wb-ubuntu-03",
529
+ ),
530
+ condition(
531
+ CorrelationFieldKey.PrincipalHost,
532
+ CorrelationOperator.Equals,
533
+ "wb-ubuntu-03",
534
+ ),
535
+ ],
536
+ "and",
537
+ );
538
+ expect(compiled.error).toBeNull();
539
+ expect(compiled.queries).toHaveLength(1);
540
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
541
+ expect(query["principalHost"]).toBe("wb-ubuntu-03");
542
+ });
543
+
544
+ test("no conditions compile to no queries and no error", () => {
545
+ const compiled: CompiledCorrelationQueries = compile([], "and");
546
+ expect(compiled.queries).toHaveLength(0);
547
+ expect(compiled.error).toBeNull();
548
+ });
549
+ });
550
+
551
+ describe("OR compilation", () => {
552
+ test("IP = X OR IP = Y collapses into ONE Includes query (hasAny already is an OR)", () => {
553
+ const compiled: CompiledCorrelationQueries = compile(
554
+ [
555
+ condition(
556
+ CorrelationFieldKey.Observable,
557
+ CorrelationOperator.Equals,
558
+ "192.168.1.20",
559
+ ),
560
+ condition(
561
+ CorrelationFieldKey.Observable,
562
+ CorrelationOperator.Equals,
563
+ "192.168.1.21",
564
+ ),
565
+ ],
566
+ "or",
567
+ );
568
+ expect(compiled.error).toBeNull();
569
+ expect(compiled.queries).toHaveLength(1);
570
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
571
+ expectBaseQuery(query);
572
+ expect(query["observables"]).toBeInstanceOf(Includes);
573
+ expect((query["observables"] as Includes).values).toEqual([
574
+ "192.168.1.20",
575
+ "192.168.1.21",
576
+ ]);
577
+ });
578
+
579
+ test("scalar equalities on the same field collapse into one IN query", () => {
580
+ const compiled: CompiledCorrelationQueries = compile(
581
+ [
582
+ condition(
583
+ CorrelationFieldKey.PrincipalUser,
584
+ CorrelationOperator.Equals,
585
+ "alice",
586
+ ),
587
+ condition(
588
+ CorrelationFieldKey.PrincipalUser,
589
+ CorrelationOperator.Equals,
590
+ "bob",
591
+ ),
592
+ ],
593
+ "or",
594
+ );
595
+ expect(compiled.queries).toHaveLength(1);
596
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
597
+ expect(query["principalUser"]).toBeInstanceOf(Includes);
598
+ expect((query["principalUser"] as Includes).values).toEqual([
599
+ "alice",
600
+ "bob",
601
+ ]);
602
+ });
603
+
604
+ test("equalities on DIFFERENT fields fan out into one query each", () => {
605
+ const compiled: CompiledCorrelationQueries = compile(
606
+ [
607
+ condition(
608
+ CorrelationFieldKey.PrincipalHost,
609
+ CorrelationOperator.Equals,
610
+ "wb-ubuntu-03",
611
+ ),
612
+ condition(
613
+ CorrelationFieldKey.TargetHost,
614
+ CorrelationOperator.Equals,
615
+ "db-primary",
616
+ ),
617
+ ],
618
+ "or",
619
+ );
620
+ expect(compiled.error).toBeNull();
621
+ expect(compiled.queries).toHaveLength(2);
622
+ for (const query of compiled.queries as Array<QueryRecord>) {
623
+ expectBaseQuery(query);
624
+ }
625
+ const keys: Array<string> = (compiled.queries as Array<QueryRecord>).map(
626
+ (query: QueryRecord) => {
627
+ return Object.keys(query)
628
+ .filter((key: string) => {
629
+ return key !== "projectId" && key !== "time";
630
+ })
631
+ .join(",");
632
+ },
633
+ );
634
+ expect(keys.sort()).toEqual(["principalHost", "targetHost"]);
635
+ });
636
+
637
+ test("non-equality conditions always get their own query", () => {
638
+ const compiled: CompiledCorrelationQueries = compile(
639
+ [
640
+ condition(
641
+ CorrelationFieldKey.Observable,
642
+ CorrelationOperator.Equals,
643
+ "wb-ubuntu-03",
644
+ ),
645
+ condition(
646
+ CorrelationFieldKey.Message,
647
+ CorrelationOperator.Contains,
648
+ "failed password",
649
+ ),
650
+ condition(
651
+ CorrelationFieldKey.Severity,
652
+ CorrelationOperator.Equals,
653
+ "Critical",
654
+ ),
655
+ ],
656
+ "or",
657
+ );
658
+ expect(compiled.error).toBeNull();
659
+ // observable= and severity= are equality groups; contains stands alone.
660
+ expect(compiled.queries).toHaveLength(3);
661
+ });
662
+
663
+ test("same-field same-value duplicates collapse before fan-out", () => {
664
+ const compiled: CompiledCorrelationQueries = compile(
665
+ [
666
+ condition(
667
+ CorrelationFieldKey.Observable,
668
+ CorrelationOperator.Equals,
669
+ "wb-ubuntu-03",
670
+ ),
671
+ condition(
672
+ CorrelationFieldKey.Observable,
673
+ CorrelationOperator.Equals,
674
+ "wb-ubuntu-03",
675
+ ),
676
+ ],
677
+ "or",
678
+ );
679
+ expect(compiled.queries).toHaveLength(1);
680
+ const query: QueryRecord = compiled.queries[0] as QueryRecord;
681
+ expect((query["observables"] as Includes).values).toEqual(["wb-ubuntu-03"]);
682
+ });
683
+
684
+ test("empty value fails in OR mode too", () => {
685
+ const compiled: CompiledCorrelationQueries = compile(
686
+ [
687
+ condition(
688
+ CorrelationFieldKey.Observable,
689
+ CorrelationOperator.Equals,
690
+ "",
691
+ ),
692
+ ],
693
+ "or",
694
+ );
695
+ expect(compiled.queries).toHaveLength(0);
696
+ expect(compiled.error).toContain("needs a value");
697
+ });
698
+ });
699
+
700
+ describe("descriptions", () => {
701
+ test("describeCorrelationCondition spells out field, operator, and value", () => {
702
+ expect(
703
+ describeCorrelationCondition(
704
+ condition(
705
+ CorrelationFieldKey.Observable,
706
+ CorrelationOperator.Equals,
707
+ "wb-ubuntu-03",
708
+ ),
709
+ ),
710
+ ).toBe('Observable is "wb-ubuntu-03"');
711
+ });
712
+
713
+ test("describeCorrelationFilter joins with the connector", () => {
714
+ const filter: CorrelationFilter = {
715
+ conditions: [
716
+ condition(
717
+ CorrelationFieldKey.PrincipalIp,
718
+ CorrelationOperator.Equals,
719
+ "192.168.1.20",
720
+ ),
721
+ condition(
722
+ CorrelationFieldKey.PrincipalUser,
723
+ CorrelationOperator.NotEquals,
724
+ "baduser1",
725
+ ),
726
+ ],
727
+ connector: "and",
728
+ };
729
+ expect(describeCorrelationFilter(filter)).toBe(
730
+ 'Principal IP is "192.168.1.20" AND Principal User is not "baduser1"',
731
+ );
732
+ });
733
+ });
734
+
735
+ describe("getEqualityObservables", () => {
736
+ test("returns only observable equality values", () => {
737
+ const filter: CorrelationFilter = {
738
+ conditions: [
739
+ condition(
740
+ CorrelationFieldKey.Observable,
741
+ CorrelationOperator.Equals,
742
+ "wb-ubuntu-03",
743
+ ),
744
+ condition(
745
+ CorrelationFieldKey.Observable,
746
+ CorrelationOperator.NotEquals,
747
+ "excluded",
748
+ ),
749
+ condition(
750
+ CorrelationFieldKey.PrincipalHost,
751
+ CorrelationOperator.Equals,
752
+ "not-an-observable-condition",
753
+ ),
754
+ condition(
755
+ CorrelationFieldKey.Observable,
756
+ CorrelationOperator.Equals,
757
+ " 192.168.1.20 ",
758
+ ),
759
+ ],
760
+ connector: "or",
761
+ };
762
+ expect(getEqualityObservables(filter)).toEqual([
763
+ "wb-ubuntu-03",
764
+ "192.168.1.20",
765
+ ]);
766
+ });
767
+ });
768
+
769
+ describe("URL round-trip", () => {
770
+ test("serialize → parse preserves conditions and connector", () => {
771
+ const filter: CorrelationFilter = {
772
+ conditions: [
773
+ condition(
774
+ CorrelationFieldKey.Observable,
775
+ CorrelationOperator.Equals,
776
+ "wb-ubuntu-03",
777
+ ),
778
+ condition(
779
+ CorrelationFieldKey.PrincipalUser,
780
+ CorrelationOperator.NotEquals,
781
+ "baduser1",
782
+ ),
783
+ condition(
784
+ CorrelationFieldKey.Message,
785
+ CorrelationOperator.Contains,
786
+ "failed password",
787
+ ),
788
+ ],
789
+ connector: "or",
790
+ };
791
+ const parsed: CorrelationFilter | null = parseCorrelationFilter(
792
+ serializeCorrelationFilter(filter),
793
+ );
794
+ expect(parsed).toEqual(filter);
795
+ });
796
+
797
+ test.each<[string, string | null]>([
798
+ ["null input", null],
799
+ ["empty string", ""],
800
+ ["not JSON", "{{{{"],
801
+ ["JSON scalar", "42"],
802
+ ["JSON null", "null"],
803
+ ["no conditions", JSON.stringify({ v: 1, j: "and", c: [] })],
804
+ [
805
+ "conditions is not an array",
806
+ JSON.stringify({ v: 1, j: "and", c: "nope" }),
807
+ ],
808
+ ])("tolerates %s by returning null", (_label: string, raw: string | null) => {
809
+ expect(parseCorrelationFilter(raw)).toBeNull();
810
+ });
811
+
812
+ test("drops malformed rows but keeps valid ones", () => {
813
+ const raw: string = JSON.stringify({
814
+ v: 1,
815
+ j: "or",
816
+ c: [
817
+ ["observable", "equals", "wb-ubuntu-03"],
818
+ ["unknownField", "equals", "x"],
819
+ ["observable", "unknown-operator", "x"],
820
+ ["observable", "equals", " "],
821
+ ["observable", "equals"],
822
+ "not-an-array",
823
+ [42, "equals", "x"],
824
+ ],
825
+ });
826
+ const parsed: CorrelationFilter | null = parseCorrelationFilter(raw);
827
+ expect(parsed).toEqual({
828
+ conditions: [
829
+ condition(
830
+ CorrelationFieldKey.Observable,
831
+ CorrelationOperator.Equals,
832
+ "wb-ubuntu-03",
833
+ ),
834
+ ],
835
+ connector: "or",
836
+ });
837
+ });
838
+
839
+ test("drops rows whose operator exists but is not offered for that field", () => {
840
+ // Severity only offers equals / not-equals.
841
+ const raw: string = JSON.stringify({
842
+ v: 1,
843
+ j: "and",
844
+ c: [["severityName", "contains", "Crit"]],
845
+ });
846
+ expect(parseCorrelationFilter(raw)).toBeNull();
847
+ });
848
+
849
+ test("any connector other than 'or' becomes 'and'", () => {
850
+ const raw: string = JSON.stringify({
851
+ v: 1,
852
+ j: "garbage",
853
+ c: [["observable", "equals", "x"]],
854
+ });
855
+ expect(parseCorrelationFilter(raw)?.connector).toBe("and");
856
+ });
857
+ });