@oneuptime/common 11.7.3 → 11.7.4

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 (365) hide show
  1. package/Models/DatabaseModels/AlertEpisodeStateTimeline.ts +1 -0
  2. package/Models/DatabaseModels/AlertStateTimeline.ts +1 -0
  3. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  4. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  5. package/Models/DatabaseModels/Index.ts +5 -0
  6. package/Models/DatabaseModels/LogDropFilter.ts +89 -0
  7. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +13 -3
  8. package/Models/DatabaseModels/RecommendationDismissal.ts +463 -0
  9. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  10. package/Models/DatabaseModels/StatusPageGroup.ts +95 -0
  11. package/Models/DatabaseModels/TraceDropFilter.ts +89 -0
  12. package/Models/DatabaseModels/WorkflowVariable.ts +5 -1
  13. package/Server/API/AlertAPI.ts +32 -17
  14. package/Server/API/BaseAPI.ts +31 -2
  15. package/Server/API/BaseAnalyticsAPI.ts +36 -2
  16. package/Server/API/CommonAPI.ts +57 -0
  17. package/Server/API/IncidentAPI.ts +60 -33
  18. package/Server/API/IncidentEpisodeAPI.ts +31 -16
  19. package/Server/API/MonitorAPI.ts +30 -0
  20. package/Server/API/MonitorTemplateAPI.ts +8 -0
  21. package/Server/API/ProbeAPI.ts +196 -15
  22. package/Server/API/ProjectAPI.ts +79 -1
  23. package/Server/API/ScheduledMaintenanceAPI.ts +33 -18
  24. package/Server/API/StatusPageAPI.ts +74 -37
  25. package/Server/API/WorkspaceNotificationRuleAPI.ts +34 -4
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.ts +527 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.ts +31 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.ts +55 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.ts +53 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  31. package/Server/Services/AlertEpisodeService.ts +47 -0
  32. package/Server/Services/AlertService.ts +125 -0
  33. package/Server/Services/BillingService.ts +98 -0
  34. package/Server/Services/DatabaseService.ts +184 -20
  35. package/Server/Services/IncidentEpisodeService.ts +47 -0
  36. package/Server/Services/IncidentService.ts +123 -0
  37. package/Server/Services/IncidentTemplateService.ts +123 -1
  38. package/Server/Services/Index.ts +2 -0
  39. package/Server/Services/LogDropFilterService.ts +133 -0
  40. package/Server/Services/MonitorProbeService.ts +94 -4
  41. package/Server/Services/MonitorService.ts +48 -43
  42. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +70 -0
  43. package/Server/Services/ProbeService.ts +66 -0
  44. package/Server/Services/ProjectService.ts +131 -7
  45. package/Server/Services/RecommendationDismissalService.ts +52 -0
  46. package/Server/Services/RunbookAgentJobService.ts +68 -7
  47. package/Server/Services/ScheduledMaintenanceService.ts +103 -0
  48. package/Server/Services/ScheduledMaintenanceTemplateService.ts +90 -0
  49. package/Server/Services/StatusPageGroupService.ts +186 -0
  50. package/Server/Services/TraceDropFilterService.ts +133 -0
  51. package/Server/Types/Workflow/Components/API/Delete.ts +12 -0
  52. package/Server/Types/Workflow/Components/API/Get.ts +12 -0
  53. package/Server/Types/Workflow/Components/API/Patch.ts +12 -0
  54. package/Server/Types/Workflow/Components/API/Post.ts +12 -0
  55. package/Server/Types/Workflow/Components/API/Put.ts +13 -0
  56. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +212 -0
  57. package/Server/Utils/DropFilterValidation.ts +127 -0
  58. package/Server/Utils/Errors.ts +5 -0
  59. package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
  60. package/Server/Utils/Monitor/MonitorIncident.ts +31 -2
  61. package/Server/Utils/Telemetry/AppMetrics.ts +31 -0
  62. package/Tests/Models/DatabaseModels/MonitorProbeColumnAccessControl.test.ts +196 -0
  63. package/Tests/Models/RecommendationDismissalModel.test.ts +269 -0
  64. package/Tests/Server/API/BaseAPIUpdatePayloadValidation.test.ts +320 -0
  65. package/Tests/Server/API/BaseAnalyticsAPIUpdatePayloadValidation.test.ts +293 -0
  66. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +164 -0
  67. package/Tests/Server/API/ProbeAPI.test.ts +422 -53
  68. package/Tests/Server/API/ProjectAPI.test.ts +180 -0
  69. package/Tests/Server/API/ProjectAPIExtendTrialBillingDisabled.test.ts +138 -0
  70. package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +458 -0
  71. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +359 -0
  72. package/Tests/Server/Infrastructure/ProcessSignalDelivery.test.ts +427 -0
  73. package/Tests/Server/Services/BillingServiceExtendTrial.test.ts +439 -0
  74. package/Tests/Server/Services/CrossProjectReferenceWriteGuard.test.ts +810 -0
  75. package/Tests/Server/Services/DatabaseServiceAtomicAddToColumns.test.ts +269 -0
  76. package/Tests/Server/Services/DatabaseServiceEmptyUpdate.test.ts +277 -0
  77. package/Tests/Server/Services/DatabaseServiceSortColumnSelect.test.ts +201 -0
  78. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +81 -23
  79. package/Tests/Server/Services/DropFilterSaveValidation.test.ts +398 -0
  80. package/Tests/Server/Services/MonitorProbeDeleteHooks.test.ts +280 -0
  81. package/Tests/Server/Services/MonitorProbeServiceProbeTenancy.test.ts +304 -0
  82. package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +262 -0
  83. package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +614 -0
  84. package/Tests/Server/Services/RecommendationDismissalService.test.ts +306 -0
  85. package/Tests/Server/Services/RepairCrossProjectIncidentReferencesMigration.test.ts +528 -0
  86. package/Tests/Server/Services/StatusPageGroupNesting.test.ts +395 -0
  87. package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +26 -21
  88. package/Tests/Server/Types/Database/Permissions/WorkflowVariableColumnPermission.test.ts +227 -0
  89. package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +285 -0
  90. package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +463 -0
  91. package/Tests/Server/Utils/DropFilterValidation.test.ts +269 -0
  92. package/Tests/Server/Utils/Telemetry/SpanUtil.test.ts +94 -0
  93. package/Tests/Types/DateUserTimezone.test.ts +52 -0
  94. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +177 -9
  95. package/Tests/Types/Monitor/MonitorStepDnsMonitor.test.ts +105 -0
  96. package/Tests/Types/Monitor/MonitorStepDnssecMonitor.test.ts +131 -0
  97. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +60 -0
  98. package/Tests/Types/Monitor/MonitorStepExternalStatusPageMonitor.test.ts +82 -0
  99. package/Tests/Types/Monitor/MonitorStepInfrastructureMonitors.test.ts +268 -0
  100. package/Tests/Types/Monitor/MonitorStepMetricMonitor.test.ts +386 -0
  101. package/Tests/Types/Monitor/MonitorStepProfileMonitor.test.ts +185 -0
  102. package/Tests/Types/Monitor/MonitorStepSnmpMonitor.test.ts +156 -0
  103. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +371 -0
  104. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +901 -0
  105. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +607 -0
  106. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +754 -0
  107. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +960 -0
  108. package/Tests/Types/RollingTime/RollingTimeUtil.test.ts +186 -0
  109. package/Tests/Types/Runbook/RunbookStepTimeout.test.ts +410 -0
  110. package/Tests/Types/Telemetry/DropFilterSampling.test.ts +241 -0
  111. package/Tests/Types/Workspace/NotificationRuleConditionUtil.test.ts +353 -0
  112. package/Tests/Types/Workspace/NotificationRuleUtil.test.ts +566 -0
  113. package/Tests/UI/Components/CodeEditor.test.tsx +174 -0
  114. package/Tests/UI/Components/ErrorBoundary.test.tsx +555 -24
  115. package/Tests/UI/Components/InfoCard.test.tsx +358 -0
  116. package/Tests/UI/Components/LogTimeRangePicker.test.tsx +138 -0
  117. package/Tests/UI/Components/Modal.test.tsx +43 -5
  118. package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +397 -0
  119. package/Tests/UI/Components/ModelTable/ColumnCustomizationModal.test.tsx +427 -0
  120. package/Tests/UI/Components/Runbook/StepTimeoutInput.test.tsx +386 -0
  121. package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +671 -0
  122. package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +404 -0
  123. package/Tests/UI/Utils/DropdownAlignment.test.ts +306 -0
  124. package/Tests/UI/Utils/TableFilterUrlState.test.ts +292 -0
  125. package/Tests/Utils/Monitor/MonitorSummaryProbeUtil.test.ts +263 -0
  126. package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +583 -0
  127. package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +1072 -0
  128. package/Tests/Utils/StatusPage/GroupTree.test.ts +583 -0
  129. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +411 -0
  130. package/Types/Date.ts +15 -6
  131. package/Types/Monitor/KubernetesAlertTemplates.ts +205 -0
  132. package/Types/Monitor/MonitorStep.ts +10 -1
  133. package/Types/Monitor/MonitorStepMetricMonitor.ts +46 -1
  134. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +413 -0
  135. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +168 -0
  136. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +175 -0
  137. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +743 -0
  138. package/Types/Permission.ts +45 -0
  139. package/Types/Recommendation/RecommendationType.ts +20 -0
  140. package/Types/Runbook/RunbookExecutionDeadline.ts +129 -0
  141. package/Types/Runbook/RunbookStepTimeout.ts +202 -0
  142. package/Types/Telemetry/DropFilterSampling.ts +92 -0
  143. package/UI/Components/AI/GenerateFromAIModal.tsx +0 -2
  144. package/UI/Components/Accordion/Accordion.tsx +10 -2
  145. package/UI/Components/BulkUpdate/BulkLabelActions.tsx +0 -1
  146. package/UI/Components/CodeEditor/CodeEditor.tsx +34 -20
  147. package/UI/Components/Date/RangeStartAndEndDateView.tsx +0 -1
  148. package/UI/Components/EditionLabel/EditionLabel.tsx +1 -27
  149. package/UI/Components/Error/PageError.tsx +0 -4
  150. package/UI/Components/ErrorBoundary.tsx +252 -15
  151. package/UI/Components/InfoCard/InfoCard.tsx +58 -1
  152. package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +34 -1
  153. package/UI/Components/Modal/Modal.tsx +16 -60
  154. package/UI/Components/ModelFormModal/ModelFormModal.tsx +0 -8
  155. package/UI/Components/ModelTable/BaseModelTable.tsx +116 -67
  156. package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +150 -47
  157. package/UI/Components/Runbook/StepTimeoutInput.tsx +173 -0
  158. package/UI/Components/StatusPage/ResourceGroupSection.tsx +231 -0
  159. package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +34 -1
  160. package/UI/Utils/DropdownAlignment.ts +162 -0
  161. package/UI/Utils/TableFilterUrlState.ts +59 -20
  162. package/Utils/API.ts +106 -2
  163. package/Utils/Monitor/MonitorSummaryProbeUtil.ts +130 -0
  164. package/Utils/NetworkDiscovery/ScanTargetUtil.ts +434 -0
  165. package/Utils/StatusPage/GroupNestingLayout.ts +343 -0
  166. package/Utils/StatusPage/GroupTree.ts +307 -0
  167. package/Utils/StatusPage/ResourceUptime.ts +90 -17
  168. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js +1 -0
  169. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js.map +1 -1
  170. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +1 -0
  171. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
  172. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  173. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  174. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  175. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  176. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  177. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  178. package/build/dist/Models/DatabaseModels/LogDropFilter.js +91 -0
  179. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  180. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +14 -4
  181. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  182. package/build/dist/Models/DatabaseModels/RecommendationDismissal.js +484 -0
  183. package/build/dist/Models/DatabaseModels/RecommendationDismissal.js.map +1 -0
  184. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  185. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/StatusPageGroup.js +94 -0
  187. package/build/dist/Models/DatabaseModels/StatusPageGroup.js.map +1 -1
  188. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +91 -0
  189. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  190. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +5 -1
  191. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  192. package/build/dist/Server/API/AlertAPI.js +22 -13
  193. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  194. package/build/dist/Server/API/BaseAPI.js +22 -1
  195. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  196. package/build/dist/Server/API/BaseAnalyticsAPI.js +24 -1
  197. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  198. package/build/dist/Server/API/CommonAPI.js +42 -0
  199. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  200. package/build/dist/Server/API/IncidentAPI.js +43 -26
  201. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  202. package/build/dist/Server/API/IncidentEpisodeAPI.js +21 -12
  203. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  204. package/build/dist/Server/API/MonitorAPI.js +23 -0
  205. package/build/dist/Server/API/MonitorAPI.js.map +1 -1
  206. package/build/dist/Server/API/MonitorTemplateAPI.js +4 -0
  207. package/build/dist/Server/API/MonitorTemplateAPI.js.map +1 -1
  208. package/build/dist/Server/API/ProbeAPI.js +131 -15
  209. package/build/dist/Server/API/ProbeAPI.js.map +1 -1
  210. package/build/dist/Server/API/ProjectAPI.js +62 -3
  211. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  212. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +23 -14
  213. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  214. package/build/dist/Server/API/StatusPageAPI.js +61 -33
  215. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  216. package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js +26 -2
  217. package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js.map +1 -1
  218. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js +397 -0
  219. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js.map +1 -0
  220. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js +16 -0
  221. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js.map +1 -0
  222. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js +30 -0
  223. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js.map +1 -0
  224. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js +34 -0
  225. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js.map +1 -0
  226. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  227. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  228. package/build/dist/Server/Services/AlertEpisodeService.js +39 -0
  229. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  230. package/build/dist/Server/Services/AlertService.js +95 -0
  231. package/build/dist/Server/Services/AlertService.js.map +1 -1
  232. package/build/dist/Server/Services/BillingService.js +71 -0
  233. package/build/dist/Server/Services/BillingService.js.map +1 -1
  234. package/build/dist/Server/Services/DatabaseService.js +140 -17
  235. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  236. package/build/dist/Server/Services/IncidentEpisodeService.js +39 -0
  237. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  238. package/build/dist/Server/Services/IncidentService.js +100 -0
  239. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  240. package/build/dist/Server/Services/IncidentTemplateService.js +97 -0
  241. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  242. package/build/dist/Server/Services/Index.js +2 -0
  243. package/build/dist/Server/Services/Index.js.map +1 -1
  244. package/build/dist/Server/Services/LogDropFilterService.js +93 -0
  245. package/build/dist/Server/Services/LogDropFilterService.js.map +1 -1
  246. package/build/dist/Server/Services/MonitorProbeService.js +73 -5
  247. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  248. package/build/dist/Server/Services/MonitorService.js +34 -39
  249. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  250. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +71 -0
  251. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
  252. package/build/dist/Server/Services/ProbeService.js +64 -0
  253. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  254. package/build/dist/Server/Services/ProjectService.js +103 -7
  255. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  256. package/build/dist/Server/Services/RecommendationDismissalService.js +50 -0
  257. package/build/dist/Server/Services/RecommendationDismissalService.js.map +1 -0
  258. package/build/dist/Server/Services/RunbookAgentJobService.js +63 -5
  259. package/build/dist/Server/Services/RunbookAgentJobService.js.map +1 -1
  260. package/build/dist/Server/Services/ScheduledMaintenanceService.js +83 -0
  261. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  262. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +65 -0
  263. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
  264. package/build/dist/Server/Services/StatusPageGroupService.js +136 -0
  265. package/build/dist/Server/Services/StatusPageGroupService.js.map +1 -1
  266. package/build/dist/Server/Services/TraceDropFilterService.js +93 -0
  267. package/build/dist/Server/Services/TraceDropFilterService.js.map +1 -1
  268. package/build/dist/Server/Types/Workflow/Components/API/Delete.js +11 -0
  269. package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
  270. package/build/dist/Server/Types/Workflow/Components/API/Get.js +11 -0
  271. package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
  272. package/build/dist/Server/Types/Workflow/Components/API/Patch.js +11 -0
  273. package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
  274. package/build/dist/Server/Types/Workflow/Components/API/Post.js +11 -0
  275. package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
  276. package/build/dist/Server/Types/Workflow/Components/API/Put.js +12 -0
  277. package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
  278. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +132 -0
  279. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -0
  280. package/build/dist/Server/Utils/DropFilterValidation.js +80 -0
  281. package/build/dist/Server/Utils/DropFilterValidation.js.map +1 -0
  282. package/build/dist/Server/Utils/Errors.js +3 -0
  283. package/build/dist/Server/Utils/Errors.js.map +1 -1
  284. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +30 -12
  285. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  286. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +38 -18
  287. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  288. package/build/dist/Server/Utils/Telemetry/AppMetrics.js +26 -0
  289. package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
  290. package/build/dist/Types/Date.js +14 -4
  291. package/build/dist/Types/Date.js.map +1 -1
  292. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +192 -0
  293. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  294. package/build/dist/Types/Monitor/MonitorStep.js +6 -1
  295. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  296. package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +32 -1
  297. package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
  298. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +294 -0
  299. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -0
  300. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +110 -0
  301. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -0
  302. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +58 -0
  303. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -0
  304. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +451 -0
  305. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -0
  306. package/build/dist/Types/Permission.js +40 -0
  307. package/build/dist/Types/Permission.js.map +1 -1
  308. package/build/dist/Types/Recommendation/RecommendationType.js +21 -0
  309. package/build/dist/Types/Recommendation/RecommendationType.js.map +1 -0
  310. package/build/dist/Types/Runbook/RunbookExecutionDeadline.js +93 -0
  311. package/build/dist/Types/Runbook/RunbookExecutionDeadline.js.map +1 -0
  312. package/build/dist/Types/Runbook/RunbookStepTimeout.js +142 -0
  313. package/build/dist/Types/Runbook/RunbookStepTimeout.js.map +1 -0
  314. package/build/dist/Types/Telemetry/DropFilterSampling.js +75 -0
  315. package/build/dist/Types/Telemetry/DropFilterSampling.js.map +1 -0
  316. package/build/dist/UI/Components/AI/GenerateFromAIModal.js +1 -2
  317. package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -1
  318. package/build/dist/UI/Components/Accordion/Accordion.js +9 -2
  319. package/build/dist/UI/Components/Accordion/Accordion.js.map +1 -1
  320. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +1 -1
  321. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
  322. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +27 -14
  323. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  324. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js +1 -1
  325. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js.map +1 -1
  326. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +2 -20
  327. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  328. package/build/dist/UI/Components/Error/PageError.js +1 -3
  329. package/build/dist/UI/Components/Error/PageError.js.map +1 -1
  330. package/build/dist/UI/Components/ErrorBoundary.js +145 -11
  331. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  332. package/build/dist/UI/Components/InfoCard/InfoCard.js +28 -1
  333. package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
  334. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +13 -2
  335. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
  336. package/build/dist/UI/Components/Modal/Modal.js +4 -32
  337. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  338. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  339. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +69 -33
  340. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  341. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +73 -32
  342. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
  343. package/build/dist/UI/Components/Runbook/StepTimeoutInput.js +101 -0
  344. package/build/dist/UI/Components/Runbook/StepTimeoutInput.js.map +1 -0
  345. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +73 -0
  346. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -0
  347. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +13 -2
  348. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
  349. package/build/dist/UI/Utils/DropdownAlignment.js +98 -0
  350. package/build/dist/UI/Utils/DropdownAlignment.js.map +1 -0
  351. package/build/dist/UI/Utils/TableFilterUrlState.js +48 -15
  352. package/build/dist/UI/Utils/TableFilterUrlState.js.map +1 -1
  353. package/build/dist/Utils/API.js +39 -2
  354. package/build/dist/Utils/API.js.map +1 -1
  355. package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js +97 -0
  356. package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js.map +1 -0
  357. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +330 -0
  358. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -0
  359. package/build/dist/Utils/StatusPage/GroupNestingLayout.js +280 -0
  360. package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -0
  361. package/build/dist/Utils/StatusPage/GroupTree.js +214 -0
  362. package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -0
  363. package/build/dist/Utils/StatusPage/ResourceUptime.js +60 -16
  364. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  365. package/package.json +1 -1
@@ -0,0 +1,583 @@
1
+ import ScanTargetUtil, {
2
+ ScanTargetNotation,
3
+ ScanTarget,
4
+ } from "../../../Utils/NetworkDiscovery/ScanTargetUtil";
5
+ import { describe, expect, it } from "@jest/globals";
6
+
7
+ /*
8
+ * Contract under test: a discovery scan target parses, counts and expands
9
+ * identically wherever it is read — the dashboard form, the server-side
10
+ * create validator, and the probe that actually sweeps it. The two notations
11
+ * have deliberately DIFFERENT address semantics (CIDR excludes network and
12
+ * broadcast; an octet range is an explicit enumeration and excludes nothing),
13
+ * so most of what follows is pinning that difference down.
14
+ */
15
+
16
+ describe("ScanTargetUtil.getNotation", () => {
17
+ it("reads a prefixed target as CIDR", () => {
18
+ expect(ScanTargetUtil.getNotation("192.168.1.0/24")).toBe(
19
+ ScanTargetNotation.Cidr,
20
+ );
21
+ });
22
+
23
+ it("reads a ranged target as an octet range", () => {
24
+ expect(ScanTargetUtil.getNotation("10.16-22.0-255.51-66")).toBe(
25
+ ScanTargetNotation.OctetRange,
26
+ );
27
+ });
28
+
29
+ it("reads a bare address as an octet range of one", () => {
30
+ expect(ScanTargetUtil.getNotation("10.0.0.5")).toBe(
31
+ ScanTargetNotation.OctetRange,
32
+ );
33
+ });
34
+
35
+ it("returns null for a target in neither notation", () => {
36
+ expect(ScanTargetUtil.getNotation("not-a-target")).toBeNull();
37
+ });
38
+
39
+ /*
40
+ * A '/' means the author meant CIDR. Falling back to the octet-range parser
41
+ * would turn a typo'd prefix into the far less useful "not a valid scan
42
+ * target" instead of "that prefix is out of range".
43
+ */
44
+ it("does not retry a malformed CIDR as an octet range", () => {
45
+ expect(ScanTargetUtil.getNotation("10.0.0.0/99")).toBeNull();
46
+ expect(ScanTargetUtil.getValidationError("10.0.0.0/99")).toContain(
47
+ "Prefix length",
48
+ );
49
+ });
50
+ });
51
+
52
+ describe("ScanTargetUtil.countHosts - CIDR", () => {
53
+ it("counts a /24 as 254 usable hosts (excludes network + broadcast)", () => {
54
+ expect(ScanTargetUtil.countHosts("192.168.1.0/24")).toBe(254);
55
+ });
56
+
57
+ it("counts a /30 as 2 usable hosts", () => {
58
+ expect(ScanTargetUtil.countHosts("10.0.0.0/30")).toBe(2);
59
+ });
60
+
61
+ it("counts /31 and /32 as every address (no network/broadcast exclusion)", () => {
62
+ expect(ScanTargetUtil.countHosts("10.0.0.0/31")).toBe(2);
63
+ expect(ScanTargetUtil.countHosts("10.0.0.5/32")).toBe(1);
64
+ });
65
+
66
+ it("counts a /8 as ~16.7M without allocating them", () => {
67
+ /*
68
+ * The whole point of counting arithmetically: this must be derivable from
69
+ * the prefix, not by building the address array.
70
+ */
71
+ expect(ScanTargetUtil.countHosts("10.0.0.0/8")).toBe(Math.pow(2, 24) - 2);
72
+ });
73
+
74
+ it("counts a /0 as the whole address space minus network + broadcast", () => {
75
+ expect(ScanTargetUtil.countHosts("0.0.0.0/0")).toBe(Math.pow(2, 32) - 2);
76
+ });
77
+
78
+ it("tolerates surrounding whitespace", () => {
79
+ expect(ScanTargetUtil.countHosts(" 192.168.1.0/24 ")).toBe(254);
80
+ });
81
+
82
+ it("returns 0 for malformed or out-of-range CIDRs", () => {
83
+ expect(ScanTargetUtil.countHosts("not-a-cidr")).toBe(0);
84
+ expect(ScanTargetUtil.countHosts("10.0.0.0/33")).toBe(0);
85
+ expect(ScanTargetUtil.countHosts("10.0.0.0/")).toBe(0);
86
+ expect(ScanTargetUtil.countHosts("/24")).toBe(0);
87
+ expect(ScanTargetUtil.countHosts("999.0.0.0/24")).toBe(0);
88
+ expect(ScanTargetUtil.countHosts("10.0.0/24")).toBe(0);
89
+ expect(ScanTargetUtil.countHosts("10.0.0.0.0/24")).toBe(0);
90
+ expect(ScanTargetUtil.countHosts("10.0.0.0/24/24")).toBe(0);
91
+ });
92
+
93
+ it("agrees with expand() for subnets small enough to expand", () => {
94
+ for (const target of [
95
+ "192.168.1.0/29",
96
+ "172.16.5.0/28",
97
+ "10.1.1.0/30",
98
+ "10.1.1.4/31",
99
+ "10.1.1.9/32",
100
+ "10.2.0.0/24",
101
+ ]) {
102
+ expect(ScanTargetUtil.countHosts(target)).toBe(
103
+ ScanTargetUtil.expand(target).length,
104
+ );
105
+ }
106
+ });
107
+ });
108
+
109
+ describe("ScanTargetUtil.countHosts - octet ranges", () => {
110
+ it("counts the product of the four octet widths", () => {
111
+ // 1 x 7 x 256 x 16
112
+ expect(ScanTargetUtil.countHosts("10.16-22.0-255.51-66")).toBe(28672);
113
+ // 1 x 3 x 256 x 16
114
+ expect(ScanTargetUtil.countHosts("10.48-50.0-255.51-66")).toBe(12288);
115
+ });
116
+
117
+ it("counts a bare address as one host", () => {
118
+ expect(ScanTargetUtil.countHosts("10.0.0.5")).toBe(1);
119
+ });
120
+
121
+ it("counts a single-octet range", () => {
122
+ expect(ScanTargetUtil.countHosts("192.168.1.10-40")).toBe(31);
123
+ });
124
+
125
+ it("counts a degenerate range (a-a) as one value for that octet", () => {
126
+ expect(ScanTargetUtil.countHosts("10.5-5.5-5.1-4")).toBe(4);
127
+ });
128
+
129
+ /*
130
+ * An octet range enumerates addresses; it has no prefix length, so there is
131
+ * no network or broadcast address to exclude. Whoever wrote 0-255 asked for
132
+ * .0 and .255 by name.
133
+ */
134
+ it("counts every address in the range, including .0 and .255", () => {
135
+ expect(ScanTargetUtil.countHosts("10.0.0.0-255")).toBe(256);
136
+ });
137
+
138
+ it("counts a full-width range without allocating it", () => {
139
+ expect(ScanTargetUtil.countHosts("0-255.0-255.0-255.0-255")).toBe(
140
+ Math.pow(256, 4),
141
+ );
142
+ });
143
+
144
+ it("tolerates surrounding whitespace", () => {
145
+ expect(ScanTargetUtil.countHosts(" 10.16-22.0-255.51-66 ")).toBe(28672);
146
+ });
147
+
148
+ it("returns 0 for out-of-range octets", () => {
149
+ expect(ScanTargetUtil.countHosts("10.256.0.1")).toBe(0);
150
+ expect(ScanTargetUtil.countHosts("10.0-256.0.1")).toBe(0);
151
+ expect(ScanTargetUtil.countHosts("300-400.0.0.1")).toBe(0);
152
+ });
153
+
154
+ it("returns 0 for a reversed range", () => {
155
+ expect(ScanTargetUtil.countHosts("10.22-16.0.1")).toBe(0);
156
+ });
157
+
158
+ it("returns 0 for the wrong number of octets", () => {
159
+ expect(ScanTargetUtil.countHosts("10.0.0")).toBe(0);
160
+ expect(ScanTargetUtil.countHosts("10.0.0.0.0")).toBe(0);
161
+ expect(ScanTargetUtil.countHosts("10.16-22.0-255")).toBe(0);
162
+ expect(ScanTargetUtil.countHosts("")).toBe(0);
163
+ expect(ScanTargetUtil.countHosts(" ")).toBe(0);
164
+ });
165
+
166
+ it("returns 0 for malformed range syntax", () => {
167
+ expect(ScanTargetUtil.countHosts("10.16-.0.1")).toBe(0);
168
+ expect(ScanTargetUtil.countHosts("10.-22.0.1")).toBe(0);
169
+ expect(ScanTargetUtil.countHosts("10.16-22-30.0.1")).toBe(0);
170
+ expect(ScanTargetUtil.countHosts("10.16 - 22.0.1")).toBe(0);
171
+ expect(ScanTargetUtil.countHosts("10.1a.0.1")).toBe(0);
172
+ expect(ScanTargetUtil.countHosts("10..0.1")).toBe(0);
173
+ expect(ScanTargetUtil.countHosts("10.0.0.1.")).toBe(0);
174
+ expect(ScanTargetUtil.countHosts(".10.0.0.1")).toBe(0);
175
+ // A negative bound reads as an empty first term, not as -22.
176
+ expect(ScanTargetUtil.countHosts("10.-22--16.0.1")).toBe(0);
177
+ });
178
+
179
+ /*
180
+ * Everything is parsed base 10, so a padded octet is the number it looks
181
+ * like and not an octal one. Worth pinning: a target that silently meant
182
+ * 10.8.0.1 instead of 10.10.0.1 would scan the wrong network.
183
+ */
184
+ it("reads zero-padded octets as base 10, never octal", () => {
185
+ expect(ScanTargetUtil.expand("010.010.0.1")).toEqual(["10.10.0.1"]);
186
+ expect(ScanTargetUtil.expand("10.0.0.08-09")).toEqual([
187
+ "10.0.0.8",
188
+ "10.0.0.9",
189
+ ]);
190
+ expect(ScanTargetUtil.countHosts("10.0.0.0/024")).toBe(254);
191
+ });
192
+
193
+ /*
194
+ * \d without the u flag is ASCII-only, so digit-lookalikes from other
195
+ * scripts are rejected rather than coerced into some other address.
196
+ */
197
+ it("rejects non-ASCII digit lookalikes", () => {
198
+ expect(ScanTargetUtil.countHosts("10.0.0.1")).toBe(0);
199
+ expect(ScanTargetUtil.countHosts("10.٠.0.1")).toBe(0);
200
+ });
201
+
202
+ it("rejects a very long target without pathological slowdown", () => {
203
+ const started: number = Date.now();
204
+ expect(ScanTargetUtil.countHosts("1".repeat(50000))).toBe(0);
205
+ expect(ScanTargetUtil.countHosts(`10.${"1-".repeat(20000)}2.0.1`)).toBe(0);
206
+ expect(Date.now() - started).toBeLessThan(2000);
207
+ });
208
+
209
+ it("accepts a target at the length gate and rejects one past it", () => {
210
+ // The widest well-formed target, comfortably inside the gate.
211
+ const widest: string = "255-255.255-255.255-255.255-255";
212
+ expect(widest.length).toBeLessThanOrEqual(ScanTargetUtil.MAX_TARGET_LENGTH);
213
+ expect(ScanTargetUtil.getValidationError(widest)).toBeNull();
214
+
215
+ expect(
216
+ ScanTargetUtil.getValidationError(
217
+ "1".repeat(ScanTargetUtil.MAX_TARGET_LENGTH + 1),
218
+ ),
219
+ ).toContain("cannot be longer than");
220
+ });
221
+
222
+ /*
223
+ * The length gate exists to bound the ERROR, not just the parse. Every
224
+ * other rejection quotes the target back — parseOctetRange quotes both the
225
+ * bad term and the whole target — and the server-side create hook runs
226
+ * ahead of the column's 100-character cap, so an unbounded echo would let a
227
+ * large request body be amplified into the exception message, the logs and
228
+ * the response body.
229
+ */
230
+ it("does not echo an over-long target back in the error message", () => {
231
+ const huge: string = `1.2.3.${"9".repeat(200000)}`;
232
+ const error: string | null = ScanTargetUtil.getValidationError(huge);
233
+
234
+ expect(error).not.toBeNull();
235
+ expect(error).not.toContain("999999");
236
+ // Constant-size message, nowhere near the size of the input.
237
+ expect(error!.length).toBeLessThan(400);
238
+ });
239
+
240
+ /*
241
+ * Wildcards are nmap syntax, not ours. Rejecting them is better than
242
+ * accepting a target that means something subtly different to the operator
243
+ * than it does to the scanner.
244
+ */
245
+ it("returns 0 for wildcard and comma-list syntax that is not supported", () => {
246
+ expect(ScanTargetUtil.countHosts("10.16-22.*.51-66")).toBe(0);
247
+ expect(ScanTargetUtil.countHosts("10.1,3,5.0.1")).toBe(0);
248
+ });
249
+
250
+ it("agrees with expand() for ranges small enough to expand", () => {
251
+ for (const target of [
252
+ "10.0.0.1-10",
253
+ "10.0.1-3.1-4",
254
+ "192.168.1.1",
255
+ "10.1-2.3-4.5-6",
256
+ "10.0.0.0-255",
257
+ ]) {
258
+ expect(ScanTargetUtil.countHosts(target)).toBe(
259
+ ScanTargetUtil.expand(target).length,
260
+ );
261
+ }
262
+ });
263
+ });
264
+
265
+ describe("ScanTargetUtil.expand - CIDR", () => {
266
+ it("expands a /29 to its 6 usable hosts, in order", () => {
267
+ expect(ScanTargetUtil.expand("192.168.1.0/29")).toEqual([
268
+ "192.168.1.1",
269
+ "192.168.1.2",
270
+ "192.168.1.3",
271
+ "192.168.1.4",
272
+ "192.168.1.5",
273
+ "192.168.1.6",
274
+ ]);
275
+ });
276
+
277
+ it("expands /31 and /32 without excluding anything", () => {
278
+ expect(ScanTargetUtil.expand("10.0.0.0/31")).toEqual([
279
+ "10.0.0.0",
280
+ "10.0.0.1",
281
+ ]);
282
+ expect(ScanTargetUtil.expand("10.0.0.5/32")).toEqual(["10.0.0.5"]);
283
+ });
284
+
285
+ /*
286
+ * The stored address need not be the network address. Masking it down is
287
+ * what makes "10.0.0.37/24" mean the same subnet as "10.0.0.0/24".
288
+ */
289
+ it("masks a non-network address down to its subnet", () => {
290
+ expect(ScanTargetUtil.expand("192.168.1.37/29")).toEqual(
291
+ ScanTargetUtil.expand("192.168.1.32/29"),
292
+ );
293
+ expect(ScanTargetUtil.expand("192.168.1.37/29")[0]).toBe("192.168.1.33");
294
+ });
295
+
296
+ /*
297
+ * A shift by 32 is a no-op in JS, so the /24 mask arithmetic has to be
298
+ * special-cased at the high end. 10.20.30.40/1 must start from 0.0.0.1,
299
+ * not from the address as typed.
300
+ */
301
+ it("masks correctly at wide prefixes where JS shift arithmetic wraps", () => {
302
+ const parsed: ScanTarget | null = ScanTargetUtil.parse("10.20.30.40/1");
303
+ expect(parsed).not.toBeNull();
304
+ expect(parsed!.networkLong).toBe(0);
305
+
306
+ const parsedZero: ScanTarget | null = ScanTargetUtil.parse("10.20.30.40/0");
307
+ expect(parsedZero!.networkLong).toBe(0);
308
+ });
309
+
310
+ it("expands the last /24 in the space without sign-bit corruption", () => {
311
+ const hosts: Array<string> = ScanTargetUtil.expand("255.255.255.0/24");
312
+ expect(hosts.length).toBe(254);
313
+ expect(hosts[0]).toBe("255.255.255.1");
314
+ expect(hosts[253]).toBe("255.255.255.254");
315
+ });
316
+
317
+ /*
318
+ * The largest block that can be expanded, sitting at the very top of the
319
+ * address space: every address here has the sign bit set, so a signed >>
320
+ * anywhere in the arithmetic would show up as a wrong octet.
321
+ */
322
+ it("expands the largest allowed block at the top of the address space", () => {
323
+ const hosts: Array<string> = ScanTargetUtil.expand("255.255.128.0/17");
324
+ expect(hosts.length).toBe(ScanTargetUtil.MAX_SCAN_HOSTS - 2);
325
+ expect(hosts[0]).toBe("255.255.128.1");
326
+ expect(hosts[hosts.length - 1]).toBe("255.255.255.254");
327
+ });
328
+
329
+ it("returns an empty array for a malformed CIDR", () => {
330
+ expect(ScanTargetUtil.expand("10.0.0.0/33")).toEqual([]);
331
+ expect(ScanTargetUtil.expand("nope/24")).toEqual([]);
332
+ });
333
+ });
334
+
335
+ describe("ScanTargetUtil.expand - octet ranges", () => {
336
+ it("expands a last-octet range", () => {
337
+ expect(ScanTargetUtil.expand("192.168.1.10-13")).toEqual([
338
+ "192.168.1.10",
339
+ "192.168.1.11",
340
+ "192.168.1.12",
341
+ "192.168.1.13",
342
+ ]);
343
+ });
344
+
345
+ it("expands a bare address to exactly that address", () => {
346
+ expect(ScanTargetUtil.expand("10.0.0.5")).toEqual(["10.0.0.5"]);
347
+ });
348
+
349
+ it("expands a multi-octet range as a cross product, in ascending order", () => {
350
+ expect(ScanTargetUtil.expand("10.1-2.3-4.5-6")).toEqual([
351
+ "10.1.3.5",
352
+ "10.1.3.6",
353
+ "10.1.4.5",
354
+ "10.1.4.6",
355
+ "10.2.3.5",
356
+ "10.2.3.6",
357
+ "10.2.4.5",
358
+ "10.2.4.6",
359
+ ]);
360
+ });
361
+
362
+ it("includes .0 and .255 when the range names them", () => {
363
+ const hosts: Array<string> = ScanTargetUtil.expand("10.0.0.0-255");
364
+ expect(hosts.length).toBe(256);
365
+ expect(hosts[0]).toBe("10.0.0.0");
366
+ expect(hosts[255]).toBe("10.0.0.255");
367
+ });
368
+
369
+ it("expands ranges in every octet position", () => {
370
+ expect(ScanTargetUtil.expand("1-2.3.4.5")).toEqual(["1.3.4.5", "2.3.4.5"]);
371
+ expect(ScanTargetUtil.expand("1.2-3.4.5")).toEqual(["1.2.4.5", "1.3.4.5"]);
372
+ expect(ScanTargetUtil.expand("1.2.3-4.5")).toEqual(["1.2.3.5", "1.2.4.5"]);
373
+ expect(ScanTargetUtil.expand("1.2.3.4-5")).toEqual(["1.2.3.4", "1.2.3.5"]);
374
+ });
375
+
376
+ it("returns an empty array for a malformed octet range", () => {
377
+ expect(ScanTargetUtil.expand("10.22-16.0.1")).toEqual([]);
378
+ expect(ScanTargetUtil.expand("10.0.0")).toEqual([]);
379
+ expect(ScanTargetUtil.expand("")).toEqual([]);
380
+ });
381
+
382
+ /*
383
+ * The example from the feature request, spot-checked at its edges. This is
384
+ * the shape octet ranges exist for: the same 16 management addresses in
385
+ * every /24 of a /13, which CIDR cannot express in one scan.
386
+ */
387
+ it("expands the motivating example to the right corners", () => {
388
+ const hosts: Array<string> = ScanTargetUtil.expand("10.16-22.0-255.51-66");
389
+
390
+ expect(hosts.length).toBe(28672);
391
+ expect(hosts[0]).toBe("10.16.0.51");
392
+ expect(hosts[15]).toBe("10.16.0.66");
393
+ expect(hosts[16]).toBe("10.16.1.51");
394
+ expect(hosts[hosts.length - 1]).toBe("10.22.255.66");
395
+
396
+ /*
397
+ * Nothing outside the named ranges leaks in. Collected into one assertion
398
+ * rather than 28,672 of them — a per-host expect() makes this test take
399
+ * seconds for no extra coverage.
400
+ */
401
+ const outOfRange: Array<string> = hosts.filter((host: string) => {
402
+ const octets: Array<number> = host.split(".").map((part: string) => {
403
+ return parseInt(part, 10);
404
+ });
405
+ return (
406
+ octets[0] !== 10 ||
407
+ octets[1]! < 16 ||
408
+ octets[1]! > 22 ||
409
+ octets[3]! < 51 ||
410
+ octets[3]! > 66
411
+ );
412
+ });
413
+ expect(outOfRange).toEqual([]);
414
+ });
415
+
416
+ it("produces no duplicates", () => {
417
+ const hosts: Array<string> = ScanTargetUtil.expand("10.1-4.1-4.1-4");
418
+ expect(new Set(hosts).size).toBe(hosts.length);
419
+ expect(hosts.length).toBe(64);
420
+ });
421
+ });
422
+
423
+ describe("ScanTargetUtil size ceiling", () => {
424
+ it("accepts a target exactly at the limit", () => {
425
+ // 128 x 256 = 32,768 = MAX_SCAN_HOSTS.
426
+ const atLimit: string = "10.0.0-127.0-255";
427
+ expect(ScanTargetUtil.countHosts(atLimit)).toBe(
428
+ ScanTargetUtil.MAX_SCAN_HOSTS,
429
+ );
430
+ expect(ScanTargetUtil.getValidationError(atLimit)).toBeNull();
431
+ });
432
+
433
+ it("rejects a target one address over the limit", () => {
434
+ // 129 x 256 = 33,024.
435
+ const overLimit: string = "10.0.0-128.0-255";
436
+ expect(ScanTargetUtil.countHosts(overLimit)).toBeGreaterThan(
437
+ ScanTargetUtil.MAX_SCAN_HOSTS,
438
+ );
439
+ expect(ScanTargetUtil.getValidationError(overLimit)).toContain(
440
+ "exceeding the",
441
+ );
442
+ });
443
+
444
+ it("accepts the motivating example, which is what the limit had to allow", () => {
445
+ expect(
446
+ ScanTargetUtil.getValidationError("10.16-22.0-255.51-66"),
447
+ ).toBeNull();
448
+ expect(
449
+ ScanTargetUtil.getValidationError("10.48-50.0-255.51-66"),
450
+ ).toBeNull();
451
+ });
452
+
453
+ it("rejects an oversized CIDR", () => {
454
+ expect(ScanTargetUtil.getValidationError("10.0.0.0/8")).toContain(
455
+ "exceeding the",
456
+ );
457
+ expect(ScanTargetUtil.getValidationError("10.0.0.0/16")).toContain(
458
+ "exceeding the",
459
+ );
460
+ });
461
+
462
+ it("accepts the largest CIDR that fits", () => {
463
+ // A /17 is 32,766 usable hosts.
464
+ expect(ScanTargetUtil.getValidationError("10.0.0.0/17")).toBeNull();
465
+ });
466
+
467
+ /*
468
+ * expand() throws rather than silently truncating or returning [] for an
469
+ * oversized target: a caller that skipped its size check has a bug, and a
470
+ * quietly short address list would turn it into a scan that reports success
471
+ * having swept a fraction of what was asked for.
472
+ */
473
+ it("throws rather than allocating when expand() is called on an oversized target", () => {
474
+ expect(() => {
475
+ return ScanTargetUtil.expand("10.0.0.0/8");
476
+ }).toThrow(/exceeding the/);
477
+
478
+ expect(() => {
479
+ return ScanTargetUtil.expand("0-255.0-255.0-255.0-255");
480
+ }).toThrow(/exceeding the/);
481
+ });
482
+
483
+ it("still returns an empty array (not a throw) for a malformed target", () => {
484
+ expect(ScanTargetUtil.expand("garbage")).toEqual([]);
485
+ });
486
+ });
487
+
488
+ describe("ScanTargetUtil.getValidationError messages", () => {
489
+ it("returns null for valid targets in both notations", () => {
490
+ expect(ScanTargetUtil.getValidationError("192.168.1.0/24")).toBeNull();
491
+ expect(
492
+ ScanTargetUtil.getValidationError("10.16-22.0-255.51-66"),
493
+ ).toBeNull();
494
+ expect(ScanTargetUtil.getValidationError("10.0.0.5")).toBeNull();
495
+ expect(ScanTargetUtil.getValidationError(" 10.0.0.5 ")).toBeNull();
496
+ });
497
+
498
+ it("asks for a target when given nothing", () => {
499
+ expect(ScanTargetUtil.getValidationError("")).toContain(
500
+ "A scan target is required",
501
+ );
502
+ expect(ScanTargetUtil.getValidationError(" ")).toContain(
503
+ "A scan target is required",
504
+ );
505
+ });
506
+
507
+ it("names the reversed octet range and suggests the fix", () => {
508
+ const error: string | null =
509
+ ScanTargetUtil.getValidationError("10.22-16.0.1");
510
+ expect(error).toContain("22-16");
511
+ expect(error).toContain("reversed");
512
+ // The suggestion is the same range written the right way round.
513
+ expect(error).toContain("16-22");
514
+ });
515
+
516
+ it("names the out-of-range octet", () => {
517
+ expect(ScanTargetUtil.getValidationError("10.0.0.256")).toContain(
518
+ "between 0 and 255",
519
+ );
520
+ expect(ScanTargetUtil.getValidationError("10.0-300.0.1")).toContain(
521
+ "between 0 and 255",
522
+ );
523
+ expect(ScanTargetUtil.getValidationError("300.0.0.0/24")).toContain(
524
+ "between 0 and 255",
525
+ );
526
+ });
527
+
528
+ it("names the out-of-range prefix", () => {
529
+ expect(ScanTargetUtil.getValidationError("10.0.0.0/33")).toContain(
530
+ "between /0 and /32",
531
+ );
532
+ });
533
+
534
+ it("explains both notations when the target is neither", () => {
535
+ const error: string | null =
536
+ ScanTargetUtil.getValidationError("hello world");
537
+ expect(error).toContain("not a valid scan target");
538
+ expect(error).toContain("CIDR");
539
+ expect(error).toContain("octet-range");
540
+ });
541
+
542
+ it("quotes the offending target back to the operator", () => {
543
+ expect(ScanTargetUtil.getValidationError("10.22-16.0.1")).toContain(
544
+ "10.22-16.0.1",
545
+ );
546
+ });
547
+
548
+ it("reports the actual size when a target is too large", () => {
549
+ const error: string | null =
550
+ ScanTargetUtil.getValidationError("10.0.0-128.0-255");
551
+ expect(error).toContain("33,024");
552
+ expect(error).toContain("32,768");
553
+ });
554
+
555
+ it("rejects non-string input without throwing", () => {
556
+ expect(
557
+ ScanTargetUtil.getValidationError(null as unknown as string),
558
+ ).toContain("A scan target is required");
559
+ expect(
560
+ ScanTargetUtil.getValidationError(undefined as unknown as string),
561
+ ).toContain("A scan target is required");
562
+ expect(ScanTargetUtil.isValid(42 as unknown as string)).toBe(false);
563
+ expect(ScanTargetUtil.countHosts({} as unknown as string)).toBe(0);
564
+ expect(ScanTargetUtil.expand([] as unknown as string)).toEqual([]);
565
+ });
566
+ });
567
+
568
+ describe("ScanTargetUtil.isValid", () => {
569
+ it("is true for well-formed targets regardless of size", () => {
570
+ /*
571
+ * isValid answers "is this syntax", NOT "will this scan" — the size
572
+ * ceiling is a separate, policy-driven check. A /8 is a perfectly valid
573
+ * CIDR that we refuse to sweep.
574
+ */
575
+ expect(ScanTargetUtil.isValid("10.0.0.0/8")).toBe(true);
576
+ expect(ScanTargetUtil.getValidationError("10.0.0.0/8")).not.toBeNull();
577
+ });
578
+
579
+ it("is false for malformed targets", () => {
580
+ expect(ScanTargetUtil.isValid("10.22-16.0.1")).toBe(false);
581
+ expect(ScanTargetUtil.isValid("")).toBe(false);
582
+ });
583
+ });