@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,677 @@
1
+ import { ClickhouseAppInstance } from "../../../../Server/Infrastructure/ClickhouseDatabase";
2
+ import { Statement } from "../../../../Server/Utils/AnalyticsDatabase/Statement";
3
+ import StatementGenerator from "../../../../Server/Utils/AnalyticsDatabase/StatementGenerator";
4
+ import "../../TestingUtils/Init";
5
+ import AnalyticsBaseModel from "../../../../Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel";
6
+ import Route from "../../../../Types/API/Route";
7
+ import AnalyticsTableEngine from "../../../../Types/AnalyticsDatabase/AnalyticsTableEngine";
8
+ import AnalyticsTableColumn from "../../../../Types/AnalyticsDatabase/TableColumn";
9
+ import TableColumnType from "../../../../Types/AnalyticsDatabase/TableColumnType";
10
+ import EqualTo from "../../../../Types/BaseDatabase/EqualTo";
11
+ import EqualToOrNull from "../../../../Types/BaseDatabase/EqualToOrNull";
12
+ import EndsWith from "../../../../Types/BaseDatabase/EndsWith";
13
+ import IncludesAll from "../../../../Types/BaseDatabase/IncludesAll";
14
+ import IncludesNone from "../../../../Types/BaseDatabase/IncludesNone";
15
+ import IsNull from "../../../../Types/BaseDatabase/IsNull";
16
+ import NotContains from "../../../../Types/BaseDatabase/NotContains";
17
+ import NotEqual from "../../../../Types/BaseDatabase/NotEqual";
18
+ import NotNull from "../../../../Types/BaseDatabase/NotNull";
19
+ import Search from "../../../../Types/BaseDatabase/Search";
20
+ import StartsWith from "../../../../Types/BaseDatabase/StartsWith";
21
+ import BadDataException from "../../../../Types/Exception/BadDataException";
22
+ import { describe, expect, test, beforeEach } from "@jest/globals";
23
+
24
+ /*
25
+ * WHERE-clause coverage for the operator branches added for the Security
26
+ * Events correlation query builder (issue #3395): explicit EqualTo /
27
+ * EqualToOrNull / NotNull, prefix/suffix/negated-substring matching on
28
+ * scalar AND Array(String) columns, substring Search over Array(String)
29
+ * (previously bound a single pattern against an Array(String) parameter —
30
+ * a guaranteed ClickHouse parse error), hasAll conjunction, and the loud
31
+ * failure for operators that have no branch for a column type (previously
32
+ * the operator OBJECT was bound as an equality value — a silent
33
+ * match-nothing filter).
34
+ *
35
+ * The shape of the model mirrors SecurityEvent where it matters: Text
36
+ * scalars like principalHost, an Array(String) observables column, and a
37
+ * Number column to pin non-Text NotNull/EqualToOrNull behavior.
38
+ */
39
+
40
+ describe("StatementGenerator toWhereStatement operator branches", () => {
41
+ class OperatorModel extends AnalyticsBaseModel {
42
+ public constructor() {
43
+ super({
44
+ tableName: "<operator-table>",
45
+ singularName: "<singular>",
46
+ pluralName: "<plural>",
47
+ tableColumns: [
48
+ new AnalyticsTableColumn({
49
+ key: "_id",
50
+ title: "<title>",
51
+ description: "<description>",
52
+ required: true,
53
+ type: TableColumnType.ObjectID,
54
+ }),
55
+ new AnalyticsTableColumn({
56
+ key: "principalHost",
57
+ title: "<title>",
58
+ description: "<description>",
59
+ required: false,
60
+ type: TableColumnType.Text,
61
+ }),
62
+ new AnalyticsTableColumn({
63
+ key: "targetPort",
64
+ title: "<title>",
65
+ description: "<description>",
66
+ required: false,
67
+ type: TableColumnType.Number,
68
+ }),
69
+ new AnalyticsTableColumn({
70
+ key: "observables",
71
+ title: "<title>",
72
+ description: "<description>",
73
+ required: true,
74
+ defaultValue: [],
75
+ type: TableColumnType.ArrayText,
76
+ }),
77
+ new AnalyticsTableColumn({
78
+ key: "attributes",
79
+ title: "<title>",
80
+ description: "<description>",
81
+ required: true,
82
+ defaultValue: {},
83
+ type: TableColumnType.MapStringString,
84
+ }),
85
+ ],
86
+ crudApiPath: new Route("route"),
87
+ primaryKeys: ["_id"],
88
+ sortKeys: ["_id"],
89
+ partitionKey: "_id",
90
+ tableEngine: AnalyticsTableEngine.MergeTree,
91
+ });
92
+ }
93
+ }
94
+
95
+ let generator: StatementGenerator<OperatorModel>;
96
+ beforeEach(() => {
97
+ generator = new StatementGenerator<OperatorModel>({
98
+ modelType: OperatorModel,
99
+ database: ClickhouseAppInstance,
100
+ });
101
+ });
102
+
103
+ describe("EqualTo wrapper on scalar columns", () => {
104
+ test("binds the WRAPPED value, exactly like bare equality", () => {
105
+ const statement: Statement = generator.toWhereStatement({
106
+ principalHost: new EqualTo("wb-ubuntu-03"),
107
+ } as any);
108
+ expect(statement.query).toBe("AND {p0:Identifier} = {p1:String}");
109
+ expect(statement.query_params).toStrictEqual({
110
+ p0: "principalHost",
111
+ p1: "wb-ubuntu-03",
112
+ });
113
+ });
114
+
115
+ test("matches the SQL produced by a bare value", () => {
116
+ const wrapped: Statement = generator.toWhereStatement({
117
+ principalHost: new EqualTo("wb-ubuntu-03"),
118
+ } as any);
119
+ const bare: Statement = generator.toWhereStatement({
120
+ principalHost: "wb-ubuntu-03",
121
+ } as any);
122
+ expect(wrapped.query).toBe(bare.query);
123
+ expect(wrapped.query_params).toStrictEqual(bare.query_params);
124
+ });
125
+
126
+ test("binds a numeric EqualTo against a Number column", () => {
127
+ const statement: Statement = generator.toWhereStatement({
128
+ targetPort: new EqualTo(443),
129
+ } as any);
130
+ expect(statement.query).toBe("AND {p0:Identifier} = {p1:Int32}");
131
+ expect(statement.query_params).toStrictEqual({
132
+ p0: "targetPort",
133
+ p1: 443,
134
+ });
135
+ });
136
+ });
137
+
138
+ describe("EqualToOrNull wrapper", () => {
139
+ test("Text column also accepts the empty-string 'not set' default", () => {
140
+ const statement: Statement = generator.toWhereStatement({
141
+ principalHost: new EqualToOrNull("wb-ubuntu-03"),
142
+ } as any);
143
+ expect(statement.query).toBe(
144
+ "AND ({p0:Identifier} = {p1:String} OR {p2:Identifier} IS NULL OR {p3:Identifier} = '')",
145
+ );
146
+ expect(statement.query_params).toStrictEqual({
147
+ p0: "principalHost",
148
+ p1: "wb-ubuntu-03",
149
+ p2: "principalHost",
150
+ p3: "principalHost",
151
+ });
152
+ });
153
+
154
+ test("non-Text column only accepts NULL as 'not set'", () => {
155
+ const statement: Statement = generator.toWhereStatement({
156
+ targetPort: new EqualToOrNull(443),
157
+ } as any);
158
+ expect(statement.query).toBe(
159
+ "AND ({p0:Identifier} = {p1:Int32} OR {p2:Identifier} IS NULL)",
160
+ );
161
+ expect(statement.query_params).toStrictEqual({
162
+ p0: "targetPort",
163
+ p1: 443,
164
+ p2: "targetPort",
165
+ });
166
+ });
167
+ });
168
+
169
+ describe("NotNull wrapper", () => {
170
+ test("Text column rejects both NULL and the empty-string default (mirror of IsNull)", () => {
171
+ const statement: Statement = generator.toWhereStatement({
172
+ principalHost: new NotNull(),
173
+ } as any);
174
+ expect(statement.query).toBe(
175
+ "AND ({p0:Identifier} IS NOT NULL AND {p1:Identifier} != '')",
176
+ );
177
+ expect(statement.query_params).toStrictEqual({
178
+ p0: "principalHost",
179
+ p1: "principalHost",
180
+ });
181
+ });
182
+
183
+ test("non-Text column checks NULL only", () => {
184
+ const statement: Statement = generator.toWhereStatement({
185
+ targetPort: new NotNull(),
186
+ } as any);
187
+ expect(statement.query).toBe("AND {p0:Identifier} IS NOT NULL");
188
+ expect(statement.query_params).toStrictEqual({
189
+ p0: "targetPort",
190
+ });
191
+ });
192
+ });
193
+
194
+ describe("StartsWith / EndsWith / NotContains on scalar columns", () => {
195
+ test("StartsWith compiles to ILIKE 'v%'", () => {
196
+ const statement: Statement = generator.toWhereStatement({
197
+ principalHost: new StartsWith("wb-"),
198
+ } as any);
199
+ expect(statement.query).toBe("AND {p0:Identifier} ILIKE {p1:String}");
200
+ expect(statement.query_params).toStrictEqual({
201
+ p0: "principalHost",
202
+ p1: "wb-%",
203
+ });
204
+ });
205
+
206
+ test("EndsWith compiles to ILIKE '%v'", () => {
207
+ const statement: Statement = generator.toWhereStatement({
208
+ principalHost: new EndsWith("-03"),
209
+ } as any);
210
+ expect(statement.query).toBe("AND {p0:Identifier} ILIKE {p1:String}");
211
+ expect(statement.query_params).toStrictEqual({
212
+ p0: "principalHost",
213
+ p1: "%-03",
214
+ });
215
+ });
216
+
217
+ test("NotContains compiles to NOT ILIKE with a NULL passthrough", () => {
218
+ /*
219
+ * A row with no value at all trivially "does not contain" the
220
+ * needle — without the IS NULL disjunct, `NOT (NULL ILIKE ...)`
221
+ * evaluates to NULL and drops the row.
222
+ */
223
+ const statement: Statement = generator.toWhereStatement({
224
+ principalHost: new NotContains("ubuntu"),
225
+ } as any);
226
+ expect(statement.query).toBe(
227
+ "AND (NOT ({p0:Identifier} ILIKE {p1:String}) OR {p2:Identifier} IS NULL)",
228
+ );
229
+ expect(statement.query_params).toStrictEqual({
230
+ p0: "principalHost",
231
+ p1: "%ubuntu%",
232
+ p2: "principalHost",
233
+ });
234
+ });
235
+ });
236
+
237
+ describe("Array(String) columns — per-element matching", () => {
238
+ test("Search compiles to arrayExists ILIKE, binding the pattern as String (not Array(String))", () => {
239
+ /*
240
+ * Before this branch the generic Search path declared the bound
241
+ * parameter with the COLUMN's type — Array(String) — while carrying
242
+ * a single '%v%' pattern string, which ClickHouse rejects at
243
+ * parameter-parse time. This is what makes a plain text filter on
244
+ * `observables` work.
245
+ */
246
+ const statement: Statement = generator.toWhereStatement({
247
+ observables: new Search("ubuntu"),
248
+ } as any);
249
+ expect(statement.query).toBe(
250
+ "AND arrayExists(x -> x ILIKE {p0:String}, {p1:Identifier})",
251
+ );
252
+ expect(statement.query_params).toStrictEqual({
253
+ p0: "%ubuntu%",
254
+ p1: "observables",
255
+ });
256
+ });
257
+
258
+ test("StartsWith compiles to arrayExists ILIKE 'v%'", () => {
259
+ const statement: Statement = generator.toWhereStatement({
260
+ observables: new StartsWith("192.168."),
261
+ } as any);
262
+ expect(statement.query).toBe(
263
+ "AND arrayExists(x -> x ILIKE {p0:String}, {p1:Identifier})",
264
+ );
265
+ expect(statement.query_params).toStrictEqual({
266
+ p0: "192.168.%",
267
+ p1: "observables",
268
+ });
269
+ });
270
+
271
+ test("EndsWith compiles to arrayExists ILIKE '%v'", () => {
272
+ const statement: Statement = generator.toWhereStatement({
273
+ observables: new EndsWith(".example.com"),
274
+ } as any);
275
+ expect(statement.query).toBe(
276
+ "AND arrayExists(x -> x ILIKE {p0:String}, {p1:Identifier})",
277
+ );
278
+ expect(statement.query_params).toStrictEqual({
279
+ p0: "%.example.com",
280
+ p1: "observables",
281
+ });
282
+ });
283
+
284
+ test("NotContains compiles to NOT arrayExists", () => {
285
+ const statement: Statement = generator.toWhereStatement({
286
+ observables: new NotContains("baduser"),
287
+ } as any);
288
+ expect(statement.query).toBe(
289
+ "AND NOT arrayExists(x -> x ILIKE {p0:String}, {p1:Identifier})",
290
+ );
291
+ expect(statement.query_params).toStrictEqual({
292
+ p0: "%baduser%",
293
+ p1: "observables",
294
+ });
295
+ });
296
+
297
+ test("IncludesAll compiles to hasAll — the 'mentions X AND Y' conjunction", () => {
298
+ const statement: Statement = generator.toWhereStatement({
299
+ observables: new IncludesAll(["wb-ubuntu-03", "192.168.1.20"]),
300
+ } as any);
301
+ expect(statement.query).toBe(
302
+ "AND hasAll({p0:Identifier}, {p1:Array(String)})",
303
+ );
304
+ expect(statement.query_params).toStrictEqual({
305
+ p0: "observables",
306
+ p1: ["wb-ubuntu-03", "192.168.1.20"],
307
+ });
308
+ });
309
+
310
+ test("empty IncludesAll drops the predicate instead of hasAll(col, [])", () => {
311
+ const statement: Statement = generator.toWhereStatement({
312
+ observables: new IncludesAll([]),
313
+ } as any);
314
+ expect(statement.query).toBe("");
315
+ expect(statement.query_params).toStrictEqual({});
316
+ });
317
+ });
318
+
319
+ describe("ILIKE metacharacter escaping", () => {
320
+ /*
321
+ * User values must match literally: "svc_" is a service-account prefix,
322
+ * not "svc followed by any character". The relational (Postgres) query
323
+ * path has escaped LIKE metacharacters for a while — these pin the
324
+ * ClickHouse path to the same contract.
325
+ */
326
+ test("StartsWith escapes _ so it cannot act as a single-char wildcard", () => {
327
+ const statement: Statement = generator.toWhereStatement({
328
+ principalHost: new StartsWith("svc_"),
329
+ } as any);
330
+ expect(statement.query_params).toStrictEqual({
331
+ p0: "principalHost",
332
+ p1: "svc\\_%",
333
+ });
334
+ });
335
+
336
+ test("EndsWith escapes % so a literal percent stays literal", () => {
337
+ const statement: Statement = generator.toWhereStatement({
338
+ principalHost: new EndsWith("50%"),
339
+ } as any);
340
+ expect(statement.query_params).toStrictEqual({
341
+ p0: "principalHost",
342
+ p1: "%50\\%",
343
+ });
344
+ });
345
+
346
+ test("NotContains escapes % — '100%' must not exclude every '100'", () => {
347
+ const statement: Statement = generator.toWhereStatement({
348
+ principalHost: new NotContains("100%"),
349
+ } as any);
350
+ expect(statement.query_params).toStrictEqual({
351
+ p0: "principalHost",
352
+ p1: "%100\\%%",
353
+ p2: "principalHost",
354
+ });
355
+ });
356
+
357
+ test("Search escapes % _ and backslash in the bound pattern", () => {
358
+ const statement: Statement = generator.toWhereStatement({
359
+ principalHost: new Search("a_b%"),
360
+ } as any);
361
+ expect(statement.query_params).toStrictEqual({
362
+ p0: "principalHost",
363
+ p1: "%a\\_b\\%%",
364
+ });
365
+ });
366
+
367
+ test("Search over Array(String) escapes a Windows-path backslash", () => {
368
+ const statement: Statement = generator.toWhereStatement({
369
+ observables: new Search("C:\\"),
370
+ } as any);
371
+ expect(statement.query_params).toStrictEqual({
372
+ p0: "%C:\\\\%",
373
+ p1: "observables",
374
+ });
375
+ });
376
+ });
377
+
378
+ describe("array-aware equality and presence", () => {
379
+ test("EqualTo on an Array(String) column means membership (has)", () => {
380
+ /*
381
+ * This is the events-table Observable filter's 'Equal To' operator —
382
+ * the scalar `col = v` form would bind a single string against an
383
+ * Array(String) parameter and fail at ClickHouse parse time.
384
+ */
385
+ const statement: Statement = generator.toWhereStatement({
386
+ observables: new EqualTo("wb-ubuntu-03"),
387
+ } as any);
388
+ expect(statement.query).toBe("AND has({p0:Identifier}, {p1:String})");
389
+ expect(statement.query_params).toStrictEqual({
390
+ p0: "observables",
391
+ p1: "wb-ubuntu-03",
392
+ });
393
+ });
394
+
395
+ test("NotEqual on an Array(String) column means does-not-mention (NOT has)", () => {
396
+ const statement: Statement = generator.toWhereStatement({
397
+ observables: new NotEqual("baduser1"),
398
+ } as any);
399
+ expect(statement.query).toBe("AND NOT has({p0:Identifier}, {p1:String})");
400
+ expect(statement.query_params).toStrictEqual({
401
+ p0: "observables",
402
+ p1: "baduser1",
403
+ });
404
+ });
405
+
406
+ test("IsNull on an Array(String) column means the empty array", () => {
407
+ // Arrays are non-Nullable — `IS NULL` would be constant-false.
408
+ const statement: Statement = generator.toWhereStatement({
409
+ observables: new IsNull(),
410
+ } as any);
411
+ expect(statement.query).toBe("AND empty({p0:Identifier})");
412
+ expect(statement.query_params).toStrictEqual({ p0: "observables" });
413
+ });
414
+
415
+ test("NotNull on an Array(String) column means at-least-one-element", () => {
416
+ // `IS NOT NULL` would be constant-true — a silent match-everything.
417
+ const statement: Statement = generator.toWhereStatement({
418
+ observables: new NotNull(),
419
+ } as any);
420
+ expect(statement.query).toBe("AND notEmpty({p0:Identifier})");
421
+ expect(statement.query_params).toStrictEqual({ p0: "observables" });
422
+ });
423
+
424
+ test("EqualToOrNull on an Array(String) column throws", () => {
425
+ expect(() => {
426
+ return generator.toWhereStatement({
427
+ observables: new EqualToOrNull("x"),
428
+ } as any);
429
+ }).toThrow(
430
+ "Unsupported query operator EqualToOrNull on column: observables",
431
+ );
432
+ });
433
+ });
434
+
435
+ describe("map/JSON column guards", () => {
436
+ /*
437
+ * Scalar operators applied to a whole Map column have per-sub-key
438
+ * forms instead; applying them to the column itself must fail with a
439
+ * BadDataException, not a cryptic ClickHouse type error.
440
+ */
441
+ test.each<[string, () => Statement]>([
442
+ [
443
+ "StartsWith",
444
+ (): Statement => {
445
+ return generator.toWhereStatement({
446
+ attributes: new StartsWith("a"),
447
+ } as any);
448
+ },
449
+ ],
450
+ [
451
+ "EqualTo",
452
+ (): Statement => {
453
+ return generator.toWhereStatement({
454
+ attributes: new EqualTo("a"),
455
+ } as any);
456
+ },
457
+ ],
458
+ [
459
+ "NotContains",
460
+ (): Statement => {
461
+ return generator.toWhereStatement({
462
+ attributes: new NotContains("a"),
463
+ } as any);
464
+ },
465
+ ],
466
+ ])(
467
+ "%s on a Map(String,String) column throws BadDataException",
468
+ (operatorName: string, compile: () => Statement) => {
469
+ expect(compile).toThrow(
470
+ `Unsupported query operator ${operatorName} on column: attributes`,
471
+ );
472
+ },
473
+ );
474
+ });
475
+
476
+ describe("unsupported operator instances fail loudly", () => {
477
+ test("IncludesAll on a scalar column throws instead of binding the operator object", () => {
478
+ expect(() => {
479
+ return generator.toWhereStatement({
480
+ principalHost: new IncludesAll(["a", "b"]),
481
+ } as any);
482
+ }).toThrow(BadDataException);
483
+ expect(() => {
484
+ return generator.toWhereStatement({
485
+ principalHost: new IncludesAll(["a", "b"]),
486
+ } as any);
487
+ }).toThrow(
488
+ "Unsupported query operator IncludesAll on column: principalHost",
489
+ );
490
+ });
491
+
492
+ test("bare values still compile to equality through the fallback", () => {
493
+ const statement: Statement = generator.toWhereStatement({
494
+ principalHost: "wb-ubuntu-03",
495
+ } as any);
496
+ expect(statement.query).toBe("AND {p0:Identifier} = {p1:String}");
497
+ expect(statement.query_params).toStrictEqual({
498
+ p0: "principalHost",
499
+ p1: "wb-ubuntu-03",
500
+ });
501
+ });
502
+ });
503
+
504
+ describe("operator arrays — several predicates AND-ed on ONE column", () => {
505
+ test("Includes + IncludesNone on an Array(String) column → hasAll-style conjunction", () => {
506
+ /*
507
+ * "mentions wb-ubuntu-03 AND does not mention baduser1" — the
508
+ * correlate builder's Exclude pivot. One column, two predicates,
509
+ * expressed as an array of operators under the key.
510
+ */
511
+ const statement: Statement = generator.toWhereStatement({
512
+ observables: [
513
+ new IncludesAll(["wb-ubuntu-03", "192.168.1.20"]),
514
+ new IncludesNone(["baduser1"]),
515
+ ],
516
+ } as any);
517
+ expect(statement.query).toBe(
518
+ "AND hasAll({p0:Identifier}, {p1:Array(String)}) " +
519
+ "AND NOT hasAny({p2:Identifier}, {p3:Array(String)})",
520
+ );
521
+ expect(statement.query_params).toStrictEqual({
522
+ p0: "observables",
523
+ p1: ["wb-ubuntu-03", "192.168.1.20"],
524
+ p2: "observables",
525
+ p3: ["baduser1"],
526
+ });
527
+ });
528
+
529
+ test("EqualTo + NotEqual on a scalar column", () => {
530
+ const statement: Statement = generator.toWhereStatement({
531
+ principalHost: [new EqualTo("wb-ubuntu-03"), new NotEqual("db-01")],
532
+ } as any);
533
+ expect(statement.query).toBe(
534
+ "AND {p0:Identifier} = {p1:String} AND {p2:Identifier} != {p3:String}",
535
+ );
536
+ expect(statement.query_params).toStrictEqual({
537
+ p0: "principalHost",
538
+ p1: "wb-ubuntu-03",
539
+ p2: "principalHost",
540
+ p3: "db-01",
541
+ });
542
+ });
543
+
544
+ test("two Search operators AND two ILIKEs", () => {
545
+ const statement: Statement = generator.toWhereStatement({
546
+ principalHost: [new Search("wb"), new Search("ubuntu")],
547
+ } as any);
548
+ expect(statement.query).toBe(
549
+ "AND {p0:Identifier} ILIKE {p1:String} AND {p2:Identifier} ILIKE {p3:String}",
550
+ );
551
+ expect(statement.query_params).toStrictEqual({
552
+ p0: "principalHost",
553
+ p1: "%wb%",
554
+ p2: "principalHost",
555
+ p3: "%ubuntu%",
556
+ });
557
+ });
558
+
559
+ test("elements whose predicate drops (empty Includes) contribute nothing", () => {
560
+ const statement: Statement = generator.toWhereStatement({
561
+ observables: [new IncludesAll([]), new IncludesNone(["baduser1"])],
562
+ } as any);
563
+ expect(statement.query).toBe(
564
+ "AND NOT hasAny({p0:Identifier}, {p1:Array(String)})",
565
+ );
566
+ expect(statement.query_params).toStrictEqual({
567
+ p0: "observables",
568
+ p1: ["baduser1"],
569
+ });
570
+ });
571
+
572
+ test("operator array composes with other columns", () => {
573
+ const statement: Statement = generator.toWhereStatement({
574
+ observables: [new IncludesAll(["a", "b"]), new IncludesNone(["c"])],
575
+ principalHost: "wb-ubuntu-03",
576
+ } as any);
577
+ expect(statement.query).toBe(
578
+ "AND hasAll({p0:Identifier}, {p1:Array(String)}) " +
579
+ "AND NOT hasAny({p2:Identifier}, {p3:Array(String)}) " +
580
+ "AND {p4:Identifier} = {p5:String}",
581
+ );
582
+ });
583
+
584
+ test("a bare string array still means exact-array equality (not operator dispatch)", () => {
585
+ const statement: Statement = generator.toWhereStatement({
586
+ observables: ["a", "b"],
587
+ } as any);
588
+ expect(statement.query).toBe("AND {p0:Identifier} = {p1:Array(String)}");
589
+ expect(statement.query_params).toStrictEqual({
590
+ p0: "observables",
591
+ p1: ["a", "b"],
592
+ });
593
+ });
594
+
595
+ test("operator arrays qualify every column reference under a table alias", () => {
596
+ /*
597
+ * The recursion forwards options, so an Exclude-pivot query embedded
598
+ * in an aggregate statement (which aliases the table) must qualify
599
+ * every fragment's column refs — no bare {pN:Identifier} columns.
600
+ */
601
+ const statement: Statement = generator.toWhereStatement(
602
+ {
603
+ observables: [new IncludesAll(["a"]), new IncludesNone(["b"])],
604
+ } as any,
605
+ { tableAlias: "<operator-table>" },
606
+ );
607
+ expect(statement.query).toBe(
608
+ "AND hasAll({p0_t:Identifier}.{p0_c:Identifier}, {p1:Array(String)}) " +
609
+ "AND NOT hasAny({p2_t:Identifier}.{p2_c:Identifier}, {p3:Array(String)})",
610
+ );
611
+ expect(statement.query_params).toStrictEqual({
612
+ p0_t: "<operator-table>",
613
+ p0_c: "observables",
614
+ p1: ["a"],
615
+ p2_t: "<operator-table>",
616
+ p2_c: "observables",
617
+ p3: ["b"],
618
+ });
619
+ });
620
+
621
+ test("an unsupported operator inside the array still throws", () => {
622
+ expect(() => {
623
+ return generator.toWhereStatement({
624
+ principalHost: [new EqualTo("x"), new IncludesAll(["a"])],
625
+ } as any);
626
+ }).toThrow(
627
+ "Unsupported query operator IncludesAll on column: principalHost",
628
+ );
629
+ });
630
+ });
631
+
632
+ describe("composition — the shapes the correlation builder emits", () => {
633
+ test("AND across different columns, mixing new and old branches", () => {
634
+ const statement: Statement = generator.toWhereStatement({
635
+ observables: new IncludesAll(["wb-ubuntu-03", "192.168.1.20"]),
636
+ principalHost: new StartsWith("wb-"),
637
+ targetPort: new NotEqual(22),
638
+ } as any);
639
+ expect(statement.query).toBe(
640
+ "AND hasAll({p0:Identifier}, {p1:Array(String)}) " +
641
+ "AND {p2:Identifier} ILIKE {p3:String} " +
642
+ "AND {p4:Identifier} != {p5:Int32}",
643
+ );
644
+ expect(statement.query_params).toStrictEqual({
645
+ p0: "observables",
646
+ p1: ["wb-ubuntu-03", "192.168.1.20"],
647
+ p2: "principalHost",
648
+ p3: "wb-%",
649
+ p4: "targetPort",
650
+ p5: 22,
651
+ });
652
+ });
653
+
654
+ test("table alias qualifies the new branches too", () => {
655
+ const statement: Statement = generator.toWhereStatement(
656
+ {
657
+ observables: new Search("ubuntu"),
658
+ principalHost: new NotNull(),
659
+ } as any,
660
+ { tableAlias: "<operator-table>" },
661
+ );
662
+ expect(statement.query).toBe(
663
+ "AND arrayExists(x -> x ILIKE {p0:String}, {p1_t:Identifier}.{p1_c:Identifier}) " +
664
+ "AND ({p2_t:Identifier}.{p2_c:Identifier} IS NOT NULL AND {p3_t:Identifier}.{p3_c:Identifier} != '')",
665
+ );
666
+ expect(statement.query_params).toStrictEqual({
667
+ p0: "%ubuntu%",
668
+ p1_t: "<operator-table>",
669
+ p1_c: "observables",
670
+ p2_t: "<operator-table>",
671
+ p2_c: "principalHost",
672
+ p3_t: "<operator-table>",
673
+ p3_c: "principalHost",
674
+ });
675
+ });
676
+ });
677
+ });