@oneuptime/common 12.0.23 → 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 (294) hide show
  1. package/Models/DatabaseModels/DetectionRule.ts +55 -0
  2. package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +27 -7
  3. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +67 -0
  4. package/Models/DatabaseModels/Project.ts +68 -0
  5. package/Models/DatabaseModels/User.ts +68 -0
  6. package/Server/API/TelemetryAPI.ts +29 -0
  7. package/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.ts +28 -0
  8. package/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.ts +49 -0
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.ts +33 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  11. package/Server/Middleware/GzipRequestBody.ts +311 -0
  12. package/Server/Middleware/MultipartFormData.ts +87 -3
  13. package/Server/Services/DetectionRuleService.ts +73 -6
  14. package/Server/Services/Index.ts +205 -0
  15. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +59 -0
  16. package/Server/Services/NetworkDeviceService.ts +148 -0
  17. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
  18. package/Server/Services/OnCallDutyPolicyFeedService.ts +1 -1
  19. package/Server/Services/ProjectService.ts +29 -19
  20. package/Server/Services/SecurityEventService.ts +90 -13
  21. package/Server/Services/StatusPageResourceService.ts +223 -0
  22. package/Server/Services/TelemetryAttributeService.ts +17 -0
  23. package/Server/Services/UserService.ts +4 -6
  24. package/Server/Types/Markdown.ts +161 -67
  25. package/Server/Utils/AI/Toolbox/OnCallTools.ts +12 -4
  26. package/Server/Utils/AnalyticsDatabase/Statement.ts +13 -1
  27. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +297 -6
  28. package/Server/Utils/Attribution.ts +4 -0
  29. package/Server/Utils/Marketing/MarketingEventUtil.ts +45 -7
  30. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +55 -3
  31. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +21 -0
  32. package/Server/Utils/StartServer.ts +12 -32
  33. package/Server/Utils/Telemetry/LlmCostBudgetEvaluator.ts +101 -4
  34. package/Server/Utils/Telemetry/LlmMetricSpend.ts +130 -0
  35. package/Server/Views/Partials/AnalyticsConsent.ejs +159 -102
  36. package/Server/Views/Partials/Head.ejs +2 -1
  37. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +776 -38
  38. package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +359 -0
  39. package/Tests/App/Dashboard/CorrelateGraph.test.tsx +865 -0
  40. package/Tests/App/Dashboard/CorrelationGraph.test.ts +346 -0
  41. package/Tests/App/Dashboard/CriteriaFilterConditionDropdown.test.tsx +256 -0
  42. package/Tests/App/Dashboard/CriteriaFilterDefaults.test.ts +738 -0
  43. package/Tests/App/Dashboard/CriteriaFilterMonitorTypeChange.test.ts +1122 -0
  44. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +283 -0
  45. package/Tests/App/Dashboard/ExternalStatusPageCriteriaFilter.test.ts +407 -0
  46. package/Tests/App/Dashboard/MetricSeriesInvestigateMenu.test.tsx +5 -14
  47. package/Tests/App/Dashboard/MonitorCriteriaActionToggles.test.tsx +426 -0
  48. package/Tests/App/Dashboard/MonitorStepsCriteriaAlignmentWiring.test.tsx +352 -0
  49. package/Tests/App/Dashboard/OnCallLayerCardOverrides.test.tsx +278 -0
  50. package/Tests/App/Dashboard/OnCallLayerShiftPreviewOverrides.test.ts +237 -0
  51. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +2 -2
  52. package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +460 -0
  53. package/Tests/App/Dashboard/SecurityEventAttributeUtil.test.ts +171 -0
  54. package/Tests/App/Dashboard/SecurityEventCorrelation.test.ts +857 -0
  55. package/Tests/App/Dashboard/SecurityEventDetailObservables.test.tsx +194 -0
  56. package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +124 -0
  57. package/Tests/App/Dashboard/SecurityEventsMonitorStepForm.test.tsx +79 -19
  58. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +382 -0
  59. package/Tests/App/StatusPage/BulkAddStatusPageMonitors.test.ts +216 -0
  60. package/Tests/App/StatusPage/BulkAddStatusPageMonitorsModal.test.tsx +590 -11
  61. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +757 -0
  62. package/Tests/Models/DiscoveryScanNameColumn.test.ts +293 -0
  63. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +564 -0
  64. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +120 -4
  65. package/Tests/Server/Middleware/GzipRequestBody.test.ts +725 -0
  66. package/Tests/Server/Middleware/MultipartFormData.test.ts +298 -0
  67. package/Tests/Server/Services/AddDetectionRuleDistinctCountColumnsMigration.test.ts +311 -0
  68. package/Tests/Server/Services/DetectionRuleService.test.ts +134 -2
  69. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +7 -1
  70. package/Tests/Server/Services/FeedRetentionConsistency.test.ts +131 -0
  71. package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +194 -0
  72. package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +800 -0
  73. package/Tests/Server/Services/OnCallScheduleAttachRosterRefresh.test.ts +244 -0
  74. package/Tests/Server/Services/SecurityEventService.test.ts +376 -0
  75. package/Tests/Server/Services/StatusPageResourceDuplicates.test.ts +703 -0
  76. package/Tests/Server/Services/TelemetryAttributeServiceSecurityEvent.test.ts +256 -0
  77. package/Tests/Server/Types/Workflow/Components/ComponentRegistryParity.test.ts +417 -0
  78. package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorWhereOperators.test.ts +677 -0
  79. package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +43 -0
  80. package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +15 -11
  81. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +369 -8
  82. package/Tests/Server/Utils/SecurityEvent/SigmaClickhouseCompiler.test.ts +35 -0
  83. package/Tests/Server/Utils/Telemetry/LlmCostBudgetEvaluator.test.ts +368 -4
  84. package/Tests/Server/Utils/Telemetry/LlmMetricSpend.test.ts +245 -0
  85. package/Tests/Server/Views/AnalyticsConsentPartial.test.ts +48 -5
  86. package/Tests/Types/Code/YamlSyntax.test.ts +396 -0
  87. package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +957 -0
  88. package/Tests/Types/Monitor/MonitorCriteriaActionValidation.test.ts +598 -0
  89. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +49 -0
  90. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +6 -6
  91. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +4 -4
  92. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +4 -3
  93. package/Tests/Types/Telemetry/LlmMetricConventions.test.ts +193 -0
  94. package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +0 -12
  95. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +1 -17
  96. package/Tests/UI/Components/CodeEditor.test.tsx +474 -10
  97. package/Tests/UI/Components/Detail/YamlField.test.tsx +105 -0
  98. package/Tests/UI/Components/EntityDropdownLabelsBulkAdd.test.tsx +319 -0
  99. package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +231 -0
  100. package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +1 -0
  101. package/Tests/UI/Components/Forms/ValidationYAML.test.ts +234 -0
  102. package/Tests/UI/Components/ModelTable/AttributeColumns.test.tsx +573 -0
  103. package/Tests/UI/Components/ModelTable/BaseModelTableAttributeColumns.test.tsx +824 -0
  104. package/Tests/UI/Components/ModelTable/ColumnCustomizationModalAddableColumns.test.tsx +707 -0
  105. package/Tests/UI/Components/SideOver.test.tsx +1 -1
  106. package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +294 -0
  107. package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +436 -0
  108. package/Tests/UI/Components/TableBulkCsvExport.test.tsx +6 -2
  109. package/Tests/UI/Components/Toggle.test.tsx +25 -0
  110. package/Tests/UI/Components/YamlEditor.test.tsx +847 -0
  111. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +252 -0
  112. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +221 -0
  113. package/Tests/Utils/NetworkDiscovery/ScanNameUtil.test.ts +312 -0
  114. package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +468 -0
  115. package/Tests/Utils/Telemetry/LlmMetricQuery.test.ts +472 -0
  116. package/Types/Code/YamlSyntax.ts +396 -0
  117. package/Types/Exception/ExceptionCode.ts +1 -0
  118. package/Types/Exception/PayloadTooLargeException.ts +8 -0
  119. package/Types/Marketing/Attribution.ts +10 -0
  120. package/Types/Marketing/MarketingEvent.ts +4 -0
  121. package/Types/Monitor/MonitorCriteriaInstance.ts +116 -56
  122. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +2 -1
  123. package/Types/SecurityEvent/DetectionFindingConstants.ts +11 -0
  124. package/Types/Telemetry/LlmMetricConventions.ts +124 -0
  125. package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +3 -0
  126. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +10 -1
  127. package/UI/Components/CodeEditor/CodeEditor.tsx +241 -79
  128. package/UI/Components/CodeEditor/YamlEditor.tsx +369 -0
  129. package/UI/Components/Detail/Detail.tsx +10 -0
  130. package/UI/Components/EntityDropdown/EntityDropdown.tsx +33 -0
  131. package/UI/Components/Forms/Fields/FormField.tsx +31 -0
  132. package/UI/Components/Forms/Types/Field.ts +8 -0
  133. package/UI/Components/Forms/Types/FormFieldSchemaType.ts +1 -0
  134. package/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.ts +2 -0
  135. package/UI/Components/Forms/Validation.ts +46 -0
  136. package/UI/Components/Input/Input.tsx +3 -0
  137. package/UI/Components/ModelTable/AttributeColumns.tsx +321 -0
  138. package/UI/Components/ModelTable/BaseModelTable.tsx +263 -14
  139. package/UI/Components/ModelTable/Column.ts +8 -0
  140. package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +310 -0
  141. package/UI/Components/ModelTable/ColumnPreference.ts +13 -1
  142. package/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.tsx +2 -2
  143. package/UI/Components/SideOver/SideOver.tsx +5 -5
  144. package/UI/Components/StatusPage/ResourceGrid.tsx +82 -2
  145. package/UI/Components/StatusPage/ResourceList.tsx +197 -38
  146. package/UI/Components/Toggle/Toggle.tsx +9 -1
  147. package/UI/Components/Types/FieldType.ts +1 -0
  148. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +73 -1
  149. package/Utils/NetworkDiscovery/ScanNameUtil.ts +181 -0
  150. package/Utils/StatusPage/ResourceExplorer.ts +258 -0
  151. package/Utils/Telemetry/LlmMetricQuery.ts +204 -0
  152. package/build/dist/Models/DatabaseModels/DetectionRule.js +57 -0
  153. package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
  154. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +27 -7
  155. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
  156. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +69 -0
  157. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  158. package/build/dist/Models/DatabaseModels/Project.js +76 -0
  159. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  160. package/build/dist/Models/DatabaseModels/User.js +76 -0
  161. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  162. package/build/dist/Server/API/TelemetryAPI.js +17 -0
  163. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  164. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js +21 -0
  165. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js.map +1 -0
  166. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js +42 -0
  167. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js.map +1 -0
  168. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js +22 -0
  169. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js.map +1 -0
  170. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  171. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  172. package/build/dist/Server/Middleware/GzipRequestBody.js +224 -0
  173. package/build/dist/Server/Middleware/GzipRequestBody.js.map +1 -0
  174. package/build/dist/Server/Middleware/MultipartFormData.js +71 -2
  175. package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
  176. package/build/dist/Server/Services/DetectionRuleService.js +49 -4
  177. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
  178. package/build/dist/Server/Services/Index.js +204 -0
  179. package/build/dist/Server/Services/Index.js.map +1 -1
  180. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +50 -0
  181. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
  182. package/build/dist/Server/Services/NetworkDeviceService.js +124 -0
  183. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  184. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +68 -13
  185. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  186. package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js +1 -1
  187. package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js.map +1 -1
  188. package/build/dist/Server/Services/ProjectService.js +25 -45
  189. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  190. package/build/dist/Server/Services/SecurityEventService.js +57 -5
  191. package/build/dist/Server/Services/SecurityEventService.js.map +1 -1
  192. package/build/dist/Server/Services/StatusPageResourceService.js +140 -0
  193. package/build/dist/Server/Services/StatusPageResourceService.js.map +1 -1
  194. package/build/dist/Server/Services/TelemetryAttributeService.js +17 -0
  195. package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
  196. package/build/dist/Server/Services/UserService.js +2 -12
  197. package/build/dist/Server/Services/UserService.js.map +1 -1
  198. package/build/dist/Server/Types/Markdown.js +147 -61
  199. package/build/dist/Server/Types/Markdown.js.map +1 -1
  200. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +12 -4
  201. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -1
  202. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +12 -1
  203. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  204. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +246 -9
  205. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  206. package/build/dist/Server/Utils/Attribution.js.map +1 -1
  207. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +27 -7
  208. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -1
  209. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +42 -7
  210. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
  211. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +18 -0
  212. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
  213. package/build/dist/Server/Utils/StartServer.js +12 -21
  214. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  215. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js +76 -5
  216. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js.map +1 -1
  217. package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js +102 -0
  218. package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js.map +1 -0
  219. package/build/dist/Types/Code/YamlSyntax.js +212 -0
  220. package/build/dist/Types/Code/YamlSyntax.js.map +1 -0
  221. package/build/dist/Types/Exception/ExceptionCode.js +1 -0
  222. package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
  223. package/build/dist/Types/Exception/PayloadTooLargeException.js +8 -0
  224. package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -0
  225. package/build/dist/Types/Marketing/Attribution.js +10 -0
  226. package/build/dist/Types/Marketing/Attribution.js.map +1 -1
  227. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +112 -51
  228. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  229. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +2 -1
  230. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
  231. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +9 -0
  232. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
  233. package/build/dist/Types/Telemetry/LlmMetricConventions.js +98 -0
  234. package/build/dist/Types/Telemetry/LlmMetricConventions.js.map +1 -0
  235. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
  236. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
  237. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +5 -2
  238. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  239. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +206 -76
  240. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  241. package/build/dist/UI/Components/CodeEditor/YamlEditor.js +201 -0
  242. package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -0
  243. package/build/dist/UI/Components/Detail/Detail.js +9 -0
  244. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  245. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +16 -1
  246. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  247. package/build/dist/UI/Components/Forms/Fields/FormField.js +14 -1
  248. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  249. package/build/dist/UI/Components/Forms/Types/Field.js.map +1 -1
  250. package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js +1 -0
  251. package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js.map +1 -1
  252. package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js +2 -0
  253. package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js.map +1 -1
  254. package/build/dist/UI/Components/Forms/Validation.js +27 -0
  255. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  256. package/build/dist/UI/Components/Input/Input.js +1 -1
  257. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  258. package/build/dist/UI/Components/ModelTable/AttributeColumns.js +159 -0
  259. package/build/dist/UI/Components/ModelTable/AttributeColumns.js.map +1 -0
  260. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +179 -17
  261. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  262. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +133 -2
  263. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
  264. package/build/dist/UI/Components/ModelTable/ColumnPreference.js +7 -1
  265. package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -1
  266. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.js +2 -2
  267. package/build/dist/UI/Components/SideOver/SideOver.js +5 -5
  268. package/build/dist/UI/Components/StatusPage/ResourceGrid.js +28 -2
  269. package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
  270. package/build/dist/UI/Components/StatusPage/ResourceList.js +87 -20
  271. package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
  272. package/build/dist/UI/Components/Toggle/Toggle.js +9 -1
  273. package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
  274. package/build/dist/UI/Components/Types/FieldType.js +1 -0
  275. package/build/dist/UI/Components/Types/FieldType.js.map +1 -1
  276. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +37 -1
  277. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
  278. package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js +120 -0
  279. package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js.map +1 -0
  280. package/build/dist/Utils/StatusPage/ResourceExplorer.js +171 -0
  281. package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -1
  282. package/build/dist/Utils/Telemetry/LlmMetricQuery.js +119 -0
  283. package/build/dist/Utils/Telemetry/LlmMetricQuery.js.map +1 -0
  284. package/jest.config.json +2 -0
  285. package/package.json +1 -1
  286. package/tsconfig.json +2 -1
  287. package/Tests/UI/Components/Toast.test.tsx +0 -197
  288. package/Tests/UI/Components/ToastStacking.test.tsx +0 -198
  289. package/UI/Components/Toast/Toast.tsx +0 -189
  290. package/UI/Components/Toast/ToastInit.tsx +0 -110
  291. package/build/dist/UI/Components/Toast/Toast.js +0 -123
  292. package/build/dist/UI/Components/Toast/Toast.js.map +0 -1
  293. package/build/dist/UI/Components/Toast/ToastInit.js +0 -53
  294. package/build/dist/UI/Components/Toast/ToastInit.js.map +0 -1
@@ -0,0 +1,194 @@
1
+ import "@testing-library/jest-dom";
2
+ import { cleanup, fireEvent, render, screen } from "@testing-library/react";
3
+ import React from "react";
4
+ import {
5
+ afterEach,
6
+ beforeEach,
7
+ describe,
8
+ expect,
9
+ jest,
10
+ test,
11
+ } from "@jest/globals";
12
+ import getJestMockFunction, { MockFunction } from "../../MockType";
13
+
14
+ /*
15
+ * The security event detail panel renders observables as pivot chips: with
16
+ * an onCorrelateObservable handler (the Correlate page embeds it that way)
17
+ * a chip pivots in place; without one (the events table) a chip deep-links
18
+ * to the Correlate page with the observable pre-seeded — URL-encoded, since
19
+ * Route.addQueryParams does not encode.
20
+ */
21
+
22
+ const navigateMock: MockFunction = getJestMockFunction();
23
+
24
+ jest.mock("../../../UI/Utils/Navigation", () => {
25
+ return {
26
+ __esModule: true,
27
+ default: {
28
+ navigate: (...args: Array<any>) => {
29
+ return navigateMock(...args);
30
+ },
31
+ },
32
+ };
33
+ });
34
+
35
+ jest.mock("../../../../App/FeatureSet/Dashboard/src/Utils/RouteMap", () => {
36
+ /*
37
+ * The mocked route keeps its :projectId placeholder and only the mocked
38
+ * populateRouteParams substitutes it — so the exact-URL assertions below
39
+ * fail if the component ever skips populateRouteParams.
40
+ */
41
+ const routeMap: Record<string, unknown> = {};
42
+ routeMap[PageMap.SECURITY_EVENTS_CORRELATE] = new Route(
43
+ "/dashboard/:projectId/security-events/correlate",
44
+ );
45
+ return {
46
+ __esModule: true,
47
+ default: routeMap,
48
+ RouteUtil: {
49
+ /*
50
+ * Fresh Route per call — addQueryParams mutates the instance, and a
51
+ * shared one would leak query params across tests.
52
+ */
53
+ populateRouteParams: (route: { toString: () => string }) => {
54
+ return new Route(
55
+ route.toString().replace(":projectId", "mock-project"),
56
+ );
57
+ },
58
+ },
59
+ };
60
+ });
61
+
62
+ /*
63
+ * The component import comes LAST: requiring it instantiates the mock
64
+ * factories above, which reference Route and PageMap — so those must be
65
+ * initialized first.
66
+ */
67
+ import SecurityEvent from "../../../Models/AnalyticsModels/SecurityEvent";
68
+ import Route from "../../../Types/API/Route";
69
+ import OcsfSeverity from "../../../Types/SecurityEvent/OcsfSeverity";
70
+ import PageMap from "../../../../App/FeatureSet/Dashboard/src/Utils/PageMap";
71
+ import SecurityEventDetail from "../../../../App/FeatureSet/Dashboard/src/Components/SecurityEvents/SecurityEventDetail";
72
+
73
+ function buildEvent(observables: Array<string>): SecurityEvent {
74
+ const event: SecurityEvent = new SecurityEvent();
75
+ event.className = "Authentication";
76
+ event.severityName = OcsfSeverity.High;
77
+ event.message = "failed password for alice";
78
+ event.observables = observables;
79
+ return event;
80
+ }
81
+
82
+ beforeEach(() => {
83
+ navigateMock.mockReset();
84
+ });
85
+
86
+ afterEach(() => {
87
+ cleanup();
88
+ });
89
+
90
+ describe("SecurityEventDetail observables", () => {
91
+ test("renders one chip per observable", () => {
92
+ render(
93
+ <SecurityEventDetail
94
+ securityEvent={buildEvent(["wb-ubuntu-03", "alice", "192.168.1.20"])}
95
+ onClose={() => {
96
+ return;
97
+ }}
98
+ />,
99
+ );
100
+
101
+ expect(
102
+ screen.getByTestId("security-event-observable-chip-0"),
103
+ ).toHaveTextContent("wb-ubuntu-03");
104
+ expect(
105
+ screen.getByTestId("security-event-observable-chip-1"),
106
+ ).toHaveTextContent("alice");
107
+ expect(
108
+ screen.getByTestId("security-event-observable-chip-2"),
109
+ ).toHaveTextContent("192.168.1.20");
110
+ });
111
+
112
+ test("empty observable strings render no chip, and no observables hides the row", () => {
113
+ render(
114
+ <SecurityEventDetail
115
+ securityEvent={buildEvent(["", "alice"])}
116
+ onClose={() => {
117
+ return;
118
+ }}
119
+ />,
120
+ );
121
+ expect(
122
+ screen.getByTestId("security-event-observable-chip-0"),
123
+ ).toHaveTextContent("alice");
124
+ expect(screen.queryByTestId("security-event-observable-chip-1")).toBeNull();
125
+
126
+ cleanup();
127
+
128
+ render(
129
+ <SecurityEventDetail
130
+ securityEvent={buildEvent([])}
131
+ onClose={() => {
132
+ return;
133
+ }}
134
+ />,
135
+ );
136
+ expect(screen.queryByText("Observables")).toBeNull();
137
+ });
138
+
139
+ test("with an onCorrelateObservable handler, a chip pivots in place instead of navigating", () => {
140
+ const onCorrelateMock: MockFunction = getJestMockFunction();
141
+
142
+ render(
143
+ <SecurityEventDetail
144
+ securityEvent={buildEvent(["wb-ubuntu-03"])}
145
+ onClose={() => {
146
+ return;
147
+ }}
148
+ onCorrelateObservable={onCorrelateMock as (observable: string) => void}
149
+ />,
150
+ );
151
+
152
+ fireEvent.click(screen.getByTestId("security-event-observable-chip-0"));
153
+
154
+ expect(onCorrelateMock).toHaveBeenCalledWith("wb-ubuntu-03");
155
+ expect(navigateMock).not.toHaveBeenCalled();
156
+ });
157
+
158
+ test("without a handler, a chip deep-links to Correlate with the observable pre-seeded", () => {
159
+ render(
160
+ <SecurityEventDetail
161
+ securityEvent={buildEvent(["wb-ubuntu-03"])}
162
+ onClose={() => {
163
+ return;
164
+ }}
165
+ />,
166
+ );
167
+
168
+ fireEvent.click(screen.getByTestId("security-event-observable-chip-0"));
169
+
170
+ expect(navigateMock).toHaveBeenCalledTimes(1);
171
+ const route: Route = navigateMock.mock.calls[0]?.[0] as Route;
172
+ expect(route.toString()).toBe(
173
+ "/dashboard/mock-project/security-events/correlate?observable=wb-ubuntu-03",
174
+ );
175
+ });
176
+
177
+ test("observable values are URL-encoded into the deep link", () => {
178
+ render(
179
+ <SecurityEventDetail
180
+ securityEvent={buildEvent(["svc account&admin"])}
181
+ onClose={() => {
182
+ return;
183
+ }}
184
+ />,
185
+ );
186
+
187
+ fireEvent.click(screen.getByTestId("security-event-observable-chip-0"));
188
+
189
+ const route: Route = navigateMock.mock.calls[0]?.[0] as Route;
190
+ expect(route.toString()).toContain(
191
+ `observable=${encodeURIComponent("svc account&admin")}`,
192
+ );
193
+ });
194
+ });
@@ -24,6 +24,10 @@ import { MemoryRouter } from "react-router-dom";
24
24
  type CapturedFormField = {
25
25
  field: Record<string, boolean>;
26
26
  title: string;
27
+ fieldType?: unknown;
28
+ stepId?: string | undefined;
29
+ required?: boolean | undefined;
30
+ validation?: { minValue?: number | undefined } | undefined;
27
31
  showIf?: ((model: Record<string, unknown>) => boolean) | undefined;
28
32
  dropdownModal?: { type: unknown } | undefined;
29
33
  };
@@ -43,6 +47,7 @@ type CapturedTableProps = {
43
47
  formFields?: Array<CapturedFormField>;
44
48
  actionButtons?: Array<CapturedActionButton>;
45
49
  createInitialValues?: Record<string, unknown>;
50
+ helpContent?: { markdown?: string | undefined } | undefined;
46
51
  };
47
52
 
48
53
  let capturedTableProps: CapturedTableProps | null = null;
@@ -58,6 +63,7 @@ jest.mock("../../../UI/Components/ModelTable/ModelTable", () => {
58
63
  });
59
64
 
60
65
  import DetectionRulesPage from "../../../../App/FeatureSet/Dashboard/src/Pages/SecurityEvents/DetectionRules";
66
+ import FormFieldSchemaType from "../../../UI/Components/Forms/Types/FormFieldSchemaType";
61
67
  import AlertSeverity from "../../../Models/DatabaseModels/AlertSeverity";
62
68
  import IncidentSeverity from "../../../Models/DatabaseModels/IncidentSeverity";
63
69
  import Project from "../../../Models/DatabaseModels/Project";
@@ -172,6 +178,124 @@ describe("Detection Rules page", () => {
172
178
  });
173
179
  });
174
180
 
181
+ describe("distinct count and match threshold fields", () => {
182
+ /*
183
+ * Issue #3398: a rule can now count unique values of one field
184
+ * (distinctCountField) instead of raw matching events, and hold fire
185
+ * until the count reaches matchCountThreshold. Both knobs are plain
186
+ * form configuration on the evaluation step — dropping either one is
187
+ * type-safe and render-safe, so the captured props are the only place
188
+ * they can be pinned.
189
+ */
190
+ test("the Distinct Count Field is an optional text field", () => {
191
+ renderPage();
192
+
193
+ const field: CapturedFormField = fieldTitled("Distinct Count Field");
194
+
195
+ expect(field.field).toEqual({ distinctCountField: true });
196
+ expect(field.fieldType).toBe(FormFieldSchemaType.Text);
197
+ expect(field.required).toBe(false);
198
+ });
199
+
200
+ test("the Match Count Threshold is a required number field that refuses values below 1", () => {
201
+ renderPage();
202
+
203
+ const field: CapturedFormField = fieldTitled("Match Count Threshold");
204
+
205
+ expect(field.field).toEqual({ matchCountThreshold: true });
206
+ expect(field.fieldType).toBe(FormFieldSchemaType.Number);
207
+ expect(field.required).toBe(true);
208
+ /*
209
+ * The service rejects 0 and negatives with a BadDataException; the
210
+ * form must stop them before submit.
211
+ */
212
+ expect(field.validation?.minValue).toBe(1);
213
+ });
214
+
215
+ test("both new fields sit on the evaluation step alongside Group By Field", () => {
216
+ renderPage();
217
+
218
+ expect(fieldTitled("Group By Field").stepId).toBe("evaluation");
219
+ expect(fieldTitled("Distinct Count Field").stepId).toBe("evaluation");
220
+ expect(fieldTitled("Match Count Threshold").stepId).toBe("evaluation");
221
+ });
222
+
223
+ test("a fresh create form seeds matchCountThreshold with the DB default of 1", () => {
224
+ /*
225
+ * matchCountThreshold is NOT NULL DEFAULT 1 in the schema and the
226
+ * form field is required — without this initial value a fresh
227
+ * create form would open with a required number field left blank.
228
+ */
229
+ renderPage();
230
+
231
+ expect(capturedTableProps?.createInitialValues).toMatchObject({
232
+ matchCountThreshold: 1,
233
+ });
234
+ });
235
+
236
+ test("the help documentation explains both new controls", () => {
237
+ renderPage();
238
+
239
+ const markdown: string = capturedTableProps?.helpContent?.markdown || "";
240
+
241
+ expect(markdown).toContain("Distinct Count Field");
242
+ expect(markdown).toContain("Match Count Threshold");
243
+ });
244
+ });
245
+
246
+ describe("the Sigma rule field is a YAML editor", () => {
247
+ /*
248
+ * The rule is YAML — SigmaRuleParser runs js-yaml over it and
249
+ * DetectionRuleService rejects a create or update whose rule does not
250
+ * compile. It was declared as Markdown, which put a rich-text toolbar
251
+ * (Bold, H1) over a Sigma rule and, worse, routed the value through an
252
+ * editor that round-trips through HTML. Indentation-sensitive YAML does
253
+ * not survive that.
254
+ */
255
+ test("it is declared as YAML", () => {
256
+ renderPage();
257
+
258
+ expect(fieldTitled("Sigma Rule (YAML)").fieldType).toBe(
259
+ FormFieldSchemaType.YAML,
260
+ );
261
+ });
262
+
263
+ test("it is not the Markdown editor", () => {
264
+ renderPage();
265
+
266
+ expect(fieldTitled("Sigma Rule (YAML)").fieldType).not.toBe(
267
+ FormFieldSchemaType.Markdown,
268
+ );
269
+ });
270
+
271
+ test("it still binds to sigmaRuleYaml on its own form step", () => {
272
+ renderPage();
273
+
274
+ const field: CapturedFormField = fieldTitled("Sigma Rule (YAML)");
275
+
276
+ expect(field.field).toEqual({ sigmaRuleYaml: true });
277
+ expect((field as unknown as { stepId?: string | undefined }).stepId).toBe(
278
+ "sigma-rule",
279
+ );
280
+ expect(
281
+ (field as unknown as { required?: boolean | undefined }).required,
282
+ ).toBe(true);
283
+ });
284
+
285
+ test("no other field on the page was switched to YAML by accident", () => {
286
+ renderPage();
287
+
288
+ const yamlFields: Array<CapturedFormField> = (
289
+ capturedTableProps?.formFields || []
290
+ ).filter((field: CapturedFormField): boolean => {
291
+ return field.fieldType === FormFieldSchemaType.YAML;
292
+ });
293
+
294
+ expect(yamlFields).toHaveLength(1);
295
+ expect(yamlFields[0]?.title).toBe("Sigma Rule (YAML)");
296
+ });
297
+ });
298
+
175
299
  describe("Create Monitor row action", () => {
176
300
  test("navigates to monitor create carrying the rule id", () => {
177
301
  renderPage();
@@ -18,19 +18,24 @@ import ProjectUtil from "../../../UI/Utils/Project";
18
18
  import ObjectID from "../../../Types/ObjectID";
19
19
 
20
20
  /*
21
- * The step form's field gating IS the feature here: Event Class was moved
22
- * out from behind the "Show Advanced Options" toggle so that watching
23
- * Detection Findings the single most useful class filter — no longer
24
- * requires knowing the toggle exists. No other test renders this form
25
- * (the view-model and type tests cover different layers), so without
26
- * this one a refactor could quietly put the field back behind the toggle
27
- * and nothing would fail.
21
+ * The step form's field gating IS the feature here: Event Class and — as
22
+ * of issue #3398 Event Severity live outside the "Show Advanced
23
+ * Options" toggle, because hiding them read as "monitors cannot filter
24
+ * by class/severity" to anyone who did not know the toggle existed.
25
+ * Only the service and attribute filters stay behind it. No other test
26
+ * renders this form (the view-model and type tests cover different
27
+ * layers), so without this one a refactor could quietly put a field
28
+ * back behind the toggle and nothing would fail.
28
29
  */
29
30
 
30
31
  const PROJECT_ID: ObjectID = new ObjectID(
31
32
  "11111111-1111-4111-8111-111111111111",
32
33
  );
33
34
 
35
+ const TELEMETRY_SERVICE_ID: ObjectID = new ObjectID(
36
+ "22222222-2222-4222-8222-222222222222",
37
+ );
38
+
34
39
  function renderForm(config?: Partial<MonitorStepSecurityEventsMonitor>): void {
35
40
  render(
36
41
  <SecurityEventsMonitorStepForm
@@ -58,20 +63,20 @@ describe("SecurityEventsMonitorStepForm field gating", () => {
58
63
  jest.restoreAllMocks();
59
64
  });
60
65
 
61
- test("Event Class is visible without opening advanced options", async () => {
66
+ test("severity and class are visible without opening advanced options", async () => {
62
67
  renderForm();
63
68
 
64
69
  // findBy: lets the preview's initial async count resolve inside act.
65
- expect(await screen.findByText("Event Class")).toBeInTheDocument();
70
+ expect(await screen.findByText("Event Severity")).toBeInTheDocument();
71
+ expect(screen.getByText("Event Class")).toBeInTheDocument();
66
72
  expect(screen.getByText("Show Advanced Options")).toBeInTheDocument();
67
73
  });
68
74
 
69
- test("severity, service and attribute filters stay behind the toggle", async () => {
75
+ test("service and attribute filters stay behind the toggle", async () => {
70
76
  renderForm();
71
77
 
72
78
  await screen.findByText("Event Class");
73
79
 
74
- expect(screen.queryByText("Event Severity")).not.toBeInTheDocument();
75
80
  expect(
76
81
  screen.queryByText("Filter by Telemetry Service"),
77
82
  ).not.toBeInTheDocument();
@@ -79,28 +84,83 @@ describe("SecurityEventsMonitorStepForm field gating", () => {
79
84
 
80
85
  fireEvent.click(screen.getByText("Show Advanced Options"));
81
86
 
82
- expect(screen.getByText("Event Severity")).toBeInTheDocument();
83
87
  expect(screen.getByText("Filter by Telemetry Service")).toBeInTheDocument();
84
88
  expect(screen.getByText("Filter by Attributes")).toBeInTheDocument();
85
89
  });
86
90
 
87
- test("a stored severity filter still opens the advanced section by itself", async () => {
91
+ test("a stored severity filter alone no longer forces the advanced section open", async () => {
88
92
  /*
89
- * Editing a monitor whose config uses an advanced filter must show
90
- * that filter immediately the auto-open behaviour classNames used
91
- * to share before it stopped being advanced.
93
+ * severityNames left the auto-open heuristic together with the
94
+ * toggle: the field is always on screen now, so a monitor that only
95
+ * filters by severity has nothing hidden worth revealing.
92
96
  */
93
97
  renderForm({ severityNames: ["High" as never] });
94
98
 
95
99
  expect(await screen.findByText("Event Severity")).toBeInTheDocument();
96
- expect(screen.getByText("Hide Advanced Options")).toBeInTheDocument();
100
+ expect(
101
+ screen.queryByText("Filter by Telemetry Service"),
102
+ ).not.toBeInTheDocument();
103
+ expect(screen.getByText("Show Advanced Options")).toBeInTheDocument();
97
104
  });
98
105
 
99
- test("a stored class filter alone no longer forces the advanced section open", async () => {
106
+ test("a stored class filter alone does not force the advanced section open", async () => {
100
107
  renderForm({ classNames: ["Detection Finding"] });
101
108
 
102
109
  expect(await screen.findByText("Event Class")).toBeInTheDocument();
103
- expect(screen.queryByText("Event Severity")).not.toBeInTheDocument();
110
+ expect(
111
+ screen.queryByText("Filter by Telemetry Service"),
112
+ ).not.toBeInTheDocument();
104
113
  expect(screen.getByText("Show Advanced Options")).toBeInTheDocument();
105
114
  });
115
+
116
+ test("a stored telemetry-service filter still opens the advanced section by itself", async () => {
117
+ /*
118
+ * Editing a monitor whose config uses a filter that IS still
119
+ * advanced must show that filter immediately — the auto-open
120
+ * behaviour severityNames used to share before it stopped being
121
+ * advanced.
122
+ */
123
+ renderForm({ telemetryServiceIds: [TELEMETRY_SERVICE_ID] });
124
+
125
+ expect(
126
+ await screen.findByText("Filter by Telemetry Service"),
127
+ ).toBeInTheDocument();
128
+ expect(screen.getByText("Hide Advanced Options")).toBeInTheDocument();
129
+ });
130
+
131
+ test("a stored attribute filter still opens the advanced section by itself", async () => {
132
+ renderForm({ attributes: { "user.name": "root" } });
133
+
134
+ expect(await screen.findByText("Filter by Attributes")).toBeInTheDocument();
135
+ expect(screen.getByText("Hide Advanced Options")).toBeInTheDocument();
136
+
137
+ /*
138
+ * The stored entry hydrates a dictionary row, and that row must
139
+ * carry the operator dropdown — the same operator restore the
140
+ * Log/Trace monitors rely on.
141
+ */
142
+ expect(screen.getByText("Operator")).toBeInTheDocument();
143
+ });
144
+
145
+ test("the attributes filter offers an operator on every new entry", async () => {
146
+ /*
147
+ * dictionaryEnableOperators is the other half of #3398: without it
148
+ * the dictionary renders a fixed "=" between key and value; with it
149
+ * each row gets an "Operator" dropdown (contains, is any of, ...).
150
+ */
151
+ renderForm();
152
+
153
+ await screen.findByText("Event Class");
154
+
155
+ fireEvent.click(screen.getByText("Show Advanced Options"));
156
+
157
+ // No rows yet, so no per-row controls either.
158
+ expect(screen.queryByText("Operator")).not.toBeInTheDocument();
159
+
160
+ fireEvent.click(screen.getByText("Add Filter by Attributes"));
161
+
162
+ expect(screen.getByText("Operator")).toBeInTheDocument();
163
+ expect(screen.getByText("Key")).toBeInTheDocument();
164
+ expect(screen.getByText("Value")).toBeInTheDocument();
165
+ });
106
166
  });