@oneuptime/common 11.7.2 → 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 (414) hide show
  1. package/Models/AnalyticsModels/KubernetesCostAllocation.ts +103 -0
  2. package/Models/DatabaseModels/AlertEpisodeStateTimeline.ts +1 -0
  3. package/Models/DatabaseModels/AlertStateTimeline.ts +1 -0
  4. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  5. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  6. package/Models/DatabaseModels/Index.ts +5 -0
  7. package/Models/DatabaseModels/LogDropFilter.ts +89 -0
  8. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +13 -3
  9. package/Models/DatabaseModels/RecommendationDismissal.ts +463 -0
  10. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  11. package/Models/DatabaseModels/StatusPageGroup.ts +95 -0
  12. package/Models/DatabaseModels/TableView.ts +40 -0
  13. package/Models/DatabaseModels/TraceDropFilter.ts +89 -0
  14. package/Models/DatabaseModels/WorkflowVariable.ts +5 -1
  15. package/Server/API/AlertAPI.ts +32 -17
  16. package/Server/API/BaseAPI.ts +31 -2
  17. package/Server/API/BaseAnalyticsAPI.ts +36 -2
  18. package/Server/API/CommonAPI.ts +57 -0
  19. package/Server/API/IncidentAPI.ts +60 -33
  20. package/Server/API/IncidentEpisodeAPI.ts +31 -16
  21. package/Server/API/MonitorAPI.ts +30 -0
  22. package/Server/API/MonitorTemplateAPI.ts +8 -0
  23. package/Server/API/ProbeAPI.ts +196 -15
  24. package/Server/API/ProjectAPI.ts +79 -1
  25. package/Server/API/ScheduledMaintenanceAPI.ts +33 -18
  26. package/Server/API/StatusPageAPI.ts +74 -37
  27. package/Server/API/WorkspaceNotificationRuleAPI.ts +34 -4
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.ts +13 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.ts +527 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.ts +31 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.ts +55 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.ts +53 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  34. package/Server/Services/AlertEpisodeService.ts +47 -0
  35. package/Server/Services/AlertService.ts +125 -0
  36. package/Server/Services/BillingService.ts +98 -0
  37. package/Server/Services/DatabaseService.ts +184 -20
  38. package/Server/Services/IncidentEpisodeService.ts +47 -0
  39. package/Server/Services/IncidentService.ts +123 -0
  40. package/Server/Services/IncidentTemplateService.ts +123 -1
  41. package/Server/Services/Index.ts +2 -0
  42. package/Server/Services/LogDropFilterService.ts +133 -0
  43. package/Server/Services/MonitorProbeService.ts +94 -4
  44. package/Server/Services/MonitorService.ts +48 -43
  45. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +70 -0
  46. package/Server/Services/ProbeService.ts +66 -0
  47. package/Server/Services/ProjectService.ts +131 -7
  48. package/Server/Services/RecommendationDismissalService.ts +52 -0
  49. package/Server/Services/RunbookAgentJobService.ts +68 -7
  50. package/Server/Services/ScheduledMaintenanceService.ts +103 -0
  51. package/Server/Services/ScheduledMaintenanceTemplateService.ts +90 -0
  52. package/Server/Services/StatusPageGroupService.ts +186 -0
  53. package/Server/Services/TraceDropFilterService.ts +133 -0
  54. package/Server/Types/Workflow/Components/API/Delete.ts +12 -0
  55. package/Server/Types/Workflow/Components/API/Get.ts +12 -0
  56. package/Server/Types/Workflow/Components/API/Patch.ts +12 -0
  57. package/Server/Types/Workflow/Components/API/Post.ts +12 -0
  58. package/Server/Types/Workflow/Components/API/Put.ts +13 -0
  59. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +212 -0
  60. package/Server/Utils/DropFilterValidation.ts +127 -0
  61. package/Server/Utils/Errors.ts +5 -0
  62. package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
  63. package/Server/Utils/Monitor/MonitorIncident.ts +31 -2
  64. package/Server/Utils/Telemetry/AppMetrics.ts +31 -0
  65. package/Tests/Models/AnalyticsModels/KubernetesCostAllocation.test.ts +16 -0
  66. package/Tests/Models/DatabaseModels/MonitorProbeColumnAccessControl.test.ts +196 -0
  67. package/Tests/Models/RecommendationDismissalModel.test.ts +269 -0
  68. package/Tests/Server/API/BaseAPIUpdatePayloadValidation.test.ts +320 -0
  69. package/Tests/Server/API/BaseAnalyticsAPIUpdatePayloadValidation.test.ts +293 -0
  70. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +164 -0
  71. package/Tests/Server/API/ProbeAPI.test.ts +422 -53
  72. package/Tests/Server/API/ProjectAPI.test.ts +180 -0
  73. package/Tests/Server/API/ProjectAPIExtendTrialBillingDisabled.test.ts +138 -0
  74. package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +458 -0
  75. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +359 -0
  76. package/Tests/Server/Infrastructure/ProcessSignalDelivery.test.ts +427 -0
  77. package/Tests/Server/Services/BillingServiceExtendTrial.test.ts +439 -0
  78. package/Tests/Server/Services/CrossProjectReferenceWriteGuard.test.ts +810 -0
  79. package/Tests/Server/Services/DatabaseServiceAtomicAddToColumns.test.ts +269 -0
  80. package/Tests/Server/Services/DatabaseServiceEmptyUpdate.test.ts +277 -0
  81. package/Tests/Server/Services/DatabaseServiceSortColumnSelect.test.ts +201 -0
  82. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +81 -23
  83. package/Tests/Server/Services/DropFilterSaveValidation.test.ts +398 -0
  84. package/Tests/Server/Services/MonitorProbeDeleteHooks.test.ts +280 -0
  85. package/Tests/Server/Services/MonitorProbeServiceProbeTenancy.test.ts +304 -0
  86. package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +262 -0
  87. package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +614 -0
  88. package/Tests/Server/Services/RecommendationDismissalService.test.ts +306 -0
  89. package/Tests/Server/Services/RepairCrossProjectIncidentReferencesMigration.test.ts +528 -0
  90. package/Tests/Server/Services/StatusPageGroupNesting.test.ts +395 -0
  91. package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +26 -21
  92. package/Tests/Server/Types/Database/Permissions/WorkflowVariableColumnPermission.test.ts +227 -0
  93. package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +285 -0
  94. package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +463 -0
  95. package/Tests/Server/Utils/DropFilterValidation.test.ts +269 -0
  96. package/Tests/Server/Utils/Telemetry/SpanUtil.test.ts +94 -0
  97. package/Tests/Types/DateUserTimezone.test.ts +52 -0
  98. package/Tests/Types/JSONFunctions.test.ts +103 -1
  99. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +177 -9
  100. package/Tests/Types/Monitor/MonitorStepDnsMonitor.test.ts +105 -0
  101. package/Tests/Types/Monitor/MonitorStepDnssecMonitor.test.ts +131 -0
  102. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +60 -0
  103. package/Tests/Types/Monitor/MonitorStepExternalStatusPageMonitor.test.ts +82 -0
  104. package/Tests/Types/Monitor/MonitorStepInfrastructureMonitors.test.ts +268 -0
  105. package/Tests/Types/Monitor/MonitorStepMetricMonitor.test.ts +386 -0
  106. package/Tests/Types/Monitor/MonitorStepProfileMonitor.test.ts +185 -0
  107. package/Tests/Types/Monitor/MonitorStepSnmpMonitor.test.ts +156 -0
  108. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +371 -0
  109. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +901 -0
  110. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +607 -0
  111. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +754 -0
  112. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +960 -0
  113. package/Tests/Types/RollingTime/RollingTimeUtil.test.ts +186 -0
  114. package/Tests/Types/Runbook/RunbookStepTimeout.test.ts +410 -0
  115. package/Tests/Types/Telemetry/DropFilterSampling.test.ts +241 -0
  116. package/Tests/Types/Workspace/NotificationRuleConditionUtil.test.ts +353 -0
  117. package/Tests/Types/Workspace/NotificationRuleUtil.test.ts +566 -0
  118. package/Tests/UI/Components/CodeEditor.test.tsx +174 -0
  119. package/Tests/UI/Components/ErrorBoundary.test.tsx +555 -24
  120. package/Tests/UI/Components/InfoCard.test.tsx +358 -0
  121. package/Tests/UI/Components/LogTimeRangePicker.test.tsx +138 -0
  122. package/Tests/UI/Components/Modal.test.tsx +43 -5
  123. package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +679 -0
  124. package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +397 -0
  125. package/Tests/UI/Components/ModelTable/ColumnCustomizationModal.test.tsx +999 -0
  126. package/Tests/UI/Components/ModelTable/ColumnPreference.test.ts +1678 -0
  127. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +1094 -0
  128. package/Tests/UI/Components/Runbook/StepTimeoutInput.test.tsx +386 -0
  129. package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +671 -0
  130. package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +404 -0
  131. package/Tests/UI/Utils/DropdownAlignment.test.ts +306 -0
  132. package/Tests/UI/Utils/TableFilterUrlState.test.ts +292 -0
  133. package/Tests/Utils/Monitor/MonitorSummaryProbeUtil.test.ts +263 -0
  134. package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +583 -0
  135. package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +1072 -0
  136. package/Tests/Utils/StatusPage/GroupTree.test.ts +583 -0
  137. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +411 -0
  138. package/Tests/Utils/UserPreferences.test.ts +563 -0
  139. package/Types/Date.ts +15 -6
  140. package/Types/JSONFunctions.ts +7 -2
  141. package/Types/Kubernetes/KubernetesCostIngest.ts +37 -1
  142. package/Types/Monitor/KubernetesAlertTemplates.ts +205 -0
  143. package/Types/Monitor/MonitorStep.ts +10 -1
  144. package/Types/Monitor/MonitorStepMetricMonitor.ts +46 -1
  145. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +413 -0
  146. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +168 -0
  147. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +175 -0
  148. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +743 -0
  149. package/Types/Permission.ts +45 -0
  150. package/Types/Recommendation/RecommendationType.ts +20 -0
  151. package/Types/Runbook/RunbookExecutionDeadline.ts +129 -0
  152. package/Types/Runbook/RunbookStepTimeout.ts +202 -0
  153. package/Types/Telemetry/DropFilterSampling.ts +92 -0
  154. package/UI/Components/AI/GenerateFromAIModal.tsx +0 -2
  155. package/UI/Components/Accordion/Accordion.tsx +10 -2
  156. package/UI/Components/BulkUpdate/BulkLabelActions.tsx +0 -1
  157. package/UI/Components/CodeEditor/CodeEditor.tsx +34 -20
  158. package/UI/Components/Date/RangeStartAndEndDateView.tsx +0 -1
  159. package/UI/Components/EditionLabel/EditionLabel.tsx +1 -27
  160. package/UI/Components/Error/PageError.tsx +0 -4
  161. package/UI/Components/ErrorBoundary.tsx +252 -15
  162. package/UI/Components/InfoCard/InfoCard.tsx +58 -1
  163. package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +34 -1
  164. package/UI/Components/MasterPage/MasterPage.tsx +65 -0
  165. package/UI/Components/Modal/Modal.tsx +16 -60
  166. package/UI/Components/ModelFormModal/ModelFormModal.tsx +0 -8
  167. package/UI/Components/ModelTable/BaseModelTable.tsx +503 -71
  168. package/UI/Components/ModelTable/Column.ts +17 -0
  169. package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +523 -0
  170. package/UI/Components/ModelTable/ColumnPreference.ts +482 -0
  171. package/UI/Components/ModelTable/CustomFieldColumns.tsx +326 -0
  172. package/UI/Components/ModelTable/TableView.tsx +24 -2
  173. package/UI/Components/ModelTable/useCustomFieldColumns.ts +150 -0
  174. package/UI/Components/Runbook/StepTimeoutInput.tsx +173 -0
  175. package/UI/Components/SideMenu/SideMenu.tsx +24 -4
  176. package/UI/Components/StatusPage/ResourceGroupSection.tsx +231 -0
  177. package/UI/Components/Table/Table.tsx +14 -1
  178. package/UI/Components/Table/TableRow.tsx +180 -175
  179. package/UI/Components/Table/Types/Column.ts +2 -0
  180. package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +34 -1
  181. package/UI/Utils/DropdownAlignment.ts +162 -0
  182. package/UI/Utils/TableFilterUrlState.ts +59 -20
  183. package/Utils/API.ts +106 -2
  184. package/Utils/Monitor/MonitorSummaryProbeUtil.ts +130 -0
  185. package/Utils/NetworkDiscovery/ScanTargetUtil.ts +434 -0
  186. package/Utils/StatusPage/GroupNestingLayout.ts +343 -0
  187. package/Utils/StatusPage/GroupTree.ts +307 -0
  188. package/Utils/StatusPage/ResourceUptime.ts +90 -17
  189. package/Utils/UserPreferences.ts +53 -0
  190. package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js +86 -0
  191. package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js +1 -0
  193. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +1 -0
  195. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
  196. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  197. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  198. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  199. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  200. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  201. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  202. package/build/dist/Models/DatabaseModels/LogDropFilter.js +91 -0
  203. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  204. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +14 -4
  205. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  206. package/build/dist/Models/DatabaseModels/RecommendationDismissal.js +484 -0
  207. package/build/dist/Models/DatabaseModels/RecommendationDismissal.js.map +1 -0
  208. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  209. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  210. package/build/dist/Models/DatabaseModels/StatusPageGroup.js +94 -0
  211. package/build/dist/Models/DatabaseModels/StatusPageGroup.js.map +1 -1
  212. package/build/dist/Models/DatabaseModels/TableView.js +40 -0
  213. package/build/dist/Models/DatabaseModels/TableView.js.map +1 -1
  214. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +91 -0
  215. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  216. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +5 -1
  217. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  218. package/build/dist/Server/API/AlertAPI.js +22 -13
  219. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  220. package/build/dist/Server/API/BaseAPI.js +22 -1
  221. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  222. package/build/dist/Server/API/BaseAnalyticsAPI.js +24 -1
  223. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  224. package/build/dist/Server/API/CommonAPI.js +42 -0
  225. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  226. package/build/dist/Server/API/IncidentAPI.js +43 -26
  227. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  228. package/build/dist/Server/API/IncidentEpisodeAPI.js +21 -12
  229. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  230. package/build/dist/Server/API/MonitorAPI.js +23 -0
  231. package/build/dist/Server/API/MonitorAPI.js.map +1 -1
  232. package/build/dist/Server/API/MonitorTemplateAPI.js +4 -0
  233. package/build/dist/Server/API/MonitorTemplateAPI.js.map +1 -1
  234. package/build/dist/Server/API/ProbeAPI.js +131 -15
  235. package/build/dist/Server/API/ProbeAPI.js.map +1 -1
  236. package/build/dist/Server/API/ProjectAPI.js +62 -3
  237. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  238. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +23 -14
  239. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  240. package/build/dist/Server/API/StatusPageAPI.js +61 -33
  241. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  242. package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js +26 -2
  243. package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js.map +1 -1
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js +12 -0
  245. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js.map +1 -0
  246. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js +397 -0
  247. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js.map +1 -0
  248. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js +16 -0
  249. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js.map +1 -0
  250. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js +30 -0
  251. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js.map +1 -0
  252. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js +34 -0
  253. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js.map +1 -0
  254. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  255. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  256. package/build/dist/Server/Services/AlertEpisodeService.js +39 -0
  257. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  258. package/build/dist/Server/Services/AlertService.js +95 -0
  259. package/build/dist/Server/Services/AlertService.js.map +1 -1
  260. package/build/dist/Server/Services/BillingService.js +71 -0
  261. package/build/dist/Server/Services/BillingService.js.map +1 -1
  262. package/build/dist/Server/Services/DatabaseService.js +140 -17
  263. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  264. package/build/dist/Server/Services/IncidentEpisodeService.js +39 -0
  265. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  266. package/build/dist/Server/Services/IncidentService.js +100 -0
  267. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  268. package/build/dist/Server/Services/IncidentTemplateService.js +97 -0
  269. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  270. package/build/dist/Server/Services/Index.js +2 -0
  271. package/build/dist/Server/Services/Index.js.map +1 -1
  272. package/build/dist/Server/Services/LogDropFilterService.js +93 -0
  273. package/build/dist/Server/Services/LogDropFilterService.js.map +1 -1
  274. package/build/dist/Server/Services/MonitorProbeService.js +73 -5
  275. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  276. package/build/dist/Server/Services/MonitorService.js +34 -39
  277. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  278. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +71 -0
  279. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
  280. package/build/dist/Server/Services/ProbeService.js +64 -0
  281. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  282. package/build/dist/Server/Services/ProjectService.js +103 -7
  283. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  284. package/build/dist/Server/Services/RecommendationDismissalService.js +50 -0
  285. package/build/dist/Server/Services/RecommendationDismissalService.js.map +1 -0
  286. package/build/dist/Server/Services/RunbookAgentJobService.js +63 -5
  287. package/build/dist/Server/Services/RunbookAgentJobService.js.map +1 -1
  288. package/build/dist/Server/Services/ScheduledMaintenanceService.js +83 -0
  289. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  290. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +65 -0
  291. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
  292. package/build/dist/Server/Services/StatusPageGroupService.js +136 -0
  293. package/build/dist/Server/Services/StatusPageGroupService.js.map +1 -1
  294. package/build/dist/Server/Services/TraceDropFilterService.js +93 -0
  295. package/build/dist/Server/Services/TraceDropFilterService.js.map +1 -1
  296. package/build/dist/Server/Types/Workflow/Components/API/Delete.js +11 -0
  297. package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
  298. package/build/dist/Server/Types/Workflow/Components/API/Get.js +11 -0
  299. package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
  300. package/build/dist/Server/Types/Workflow/Components/API/Patch.js +11 -0
  301. package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
  302. package/build/dist/Server/Types/Workflow/Components/API/Post.js +11 -0
  303. package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
  304. package/build/dist/Server/Types/Workflow/Components/API/Put.js +12 -0
  305. package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
  306. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +132 -0
  307. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -0
  308. package/build/dist/Server/Utils/DropFilterValidation.js +80 -0
  309. package/build/dist/Server/Utils/DropFilterValidation.js.map +1 -0
  310. package/build/dist/Server/Utils/Errors.js +3 -0
  311. package/build/dist/Server/Utils/Errors.js.map +1 -1
  312. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +30 -12
  313. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  314. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +38 -18
  315. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  316. package/build/dist/Server/Utils/Telemetry/AppMetrics.js +26 -0
  317. package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
  318. package/build/dist/Types/Date.js +14 -4
  319. package/build/dist/Types/Date.js.map +1 -1
  320. package/build/dist/Types/JSONFunctions.js +8 -3
  321. package/build/dist/Types/JSONFunctions.js.map +1 -1
  322. package/build/dist/Types/Kubernetes/KubernetesCostIngest.js.map +1 -1
  323. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +192 -0
  324. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  325. package/build/dist/Types/Monitor/MonitorStep.js +6 -1
  326. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  327. package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +32 -1
  328. package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
  329. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +294 -0
  330. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -0
  331. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +110 -0
  332. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -0
  333. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +58 -0
  334. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -0
  335. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +451 -0
  336. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -0
  337. package/build/dist/Types/Permission.js +40 -0
  338. package/build/dist/Types/Permission.js.map +1 -1
  339. package/build/dist/Types/Recommendation/RecommendationType.js +21 -0
  340. package/build/dist/Types/Recommendation/RecommendationType.js.map +1 -0
  341. package/build/dist/Types/Runbook/RunbookExecutionDeadline.js +93 -0
  342. package/build/dist/Types/Runbook/RunbookExecutionDeadline.js.map +1 -0
  343. package/build/dist/Types/Runbook/RunbookStepTimeout.js +142 -0
  344. package/build/dist/Types/Runbook/RunbookStepTimeout.js.map +1 -0
  345. package/build/dist/Types/Telemetry/DropFilterSampling.js +75 -0
  346. package/build/dist/Types/Telemetry/DropFilterSampling.js.map +1 -0
  347. package/build/dist/UI/Components/AI/GenerateFromAIModal.js +1 -2
  348. package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -1
  349. package/build/dist/UI/Components/Accordion/Accordion.js +9 -2
  350. package/build/dist/UI/Components/Accordion/Accordion.js.map +1 -1
  351. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +1 -1
  352. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
  353. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +27 -14
  354. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  355. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js +1 -1
  356. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js.map +1 -1
  357. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +2 -20
  358. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  359. package/build/dist/UI/Components/Error/PageError.js +1 -3
  360. package/build/dist/UI/Components/Error/PageError.js.map +1 -1
  361. package/build/dist/UI/Components/ErrorBoundary.js +145 -11
  362. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  363. package/build/dist/UI/Components/InfoCard/InfoCard.js +28 -1
  364. package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
  365. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +13 -2
  366. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
  367. package/build/dist/UI/Components/MasterPage/MasterPage.js +50 -1
  368. package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
  369. package/build/dist/UI/Components/Modal/Modal.js +4 -32
  370. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  371. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  372. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +308 -40
  373. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  374. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +230 -0
  375. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -0
  376. package/build/dist/UI/Components/ModelTable/ColumnPreference.js +258 -0
  377. package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -0
  378. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +168 -0
  379. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -0
  380. package/build/dist/UI/Components/ModelTable/TableView.js +13 -2
  381. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  382. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +84 -0
  383. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -0
  384. package/build/dist/UI/Components/Runbook/StepTimeoutInput.js +101 -0
  385. package/build/dist/UI/Components/Runbook/StepTimeoutInput.js.map +1 -0
  386. package/build/dist/UI/Components/SideMenu/SideMenu.js +15 -5
  387. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  388. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +73 -0
  389. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -0
  390. package/build/dist/UI/Components/Table/Table.js +15 -2
  391. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  392. package/build/dist/UI/Components/Table/TableRow.js +11 -6
  393. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  394. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +13 -2
  395. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
  396. package/build/dist/UI/Utils/DropdownAlignment.js +98 -0
  397. package/build/dist/UI/Utils/DropdownAlignment.js.map +1 -0
  398. package/build/dist/UI/Utils/TableFilterUrlState.js +48 -15
  399. package/build/dist/UI/Utils/TableFilterUrlState.js.map +1 -1
  400. package/build/dist/Utils/API.js +39 -2
  401. package/build/dist/Utils/API.js.map +1 -1
  402. package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js +97 -0
  403. package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js.map +1 -0
  404. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +330 -0
  405. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -0
  406. package/build/dist/Utils/StatusPage/GroupNestingLayout.js +280 -0
  407. package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -0
  408. package/build/dist/Utils/StatusPage/GroupTree.js +214 -0
  409. package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -0
  410. package/build/dist/Utils/StatusPage/ResourceUptime.js +60 -16
  411. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  412. package/build/dist/Utils/UserPreferences.js +33 -0
  413. package/build/dist/Utils/UserPreferences.js.map +1 -1
  414. package/package.json +1 -1
@@ -0,0 +1,395 @@
1
+ import StatusPageGroupService from "../../../Server/Services/StatusPageGroupService";
2
+ import StatusPageGroup from "../../../Models/DatabaseModels/StatusPageGroup";
3
+ import BadDataException from "../../../Types/Exception/BadDataException";
4
+ import ObjectID from "../../../Types/ObjectID";
5
+ import PositiveNumber from "../../../Types/PositiveNumber";
6
+ import CreateBy from "../../../Server/Types/Database/CreateBy";
7
+ import UpdateBy from "../../../Server/Types/Database/UpdateBy";
8
+ import StatusPageGroupTreeUtil from "../../../Utils/StatusPage/GroupTree";
9
+ import { describe, expect, it, afterEach } from "@jest/globals";
10
+
11
+ /*
12
+ * Contract under test - the write side of nested status page groups.
13
+ *
14
+ * The parent pointer is a plain nullable column, so the service is the only
15
+ * thing standing between a well formed tree and one that cannot be rendered or
16
+ * rolled up. It has to reject, on both create and update:
17
+ *
18
+ * - a parent on a different status page (groups roll up per page),
19
+ * - a group parented to itself,
20
+ * - a group parented to one of its own sub groups (a cycle - which would
21
+ * make the group unreachable from any root and its rollups circular),
22
+ * - a move that pushes the group, or anything already nested under it,
23
+ * past the nesting limit.
24
+ *
25
+ * And it must not pay for any of that when the write does not touch the parent.
26
+ */
27
+
28
+ const STATUS_PAGE_ID: ObjectID = new ObjectID(
29
+ "11111111-1111-4111-8111-111111111111",
30
+ );
31
+ const OTHER_STATUS_PAGE_ID: ObjectID = new ObjectID(
32
+ "22222222-2222-4222-8222-222222222222",
33
+ );
34
+ const PROJECT_ID: ObjectID = new ObjectID(
35
+ "33333333-3333-4333-8333-333333333333",
36
+ );
37
+
38
+ function groupId(index: number): ObjectID {
39
+ const suffix: string = index.toString().padStart(12, "0");
40
+ return new ObjectID(`aaaaaaaa-aaaa-4aaa-8aaa-${suffix}`);
41
+ }
42
+
43
+ function makeGroup(data: {
44
+ id: ObjectID;
45
+ parentId?: ObjectID | undefined;
46
+ statusPageId?: ObjectID | undefined;
47
+ }): StatusPageGroup {
48
+ const group: StatusPageGroup = new StatusPageGroup();
49
+ group._id = data.id.toString();
50
+ group.statusPageId = data.statusPageId || STATUS_PAGE_ID;
51
+
52
+ if (data.parentId) {
53
+ group.parentStatusPageGroupId = data.parentId;
54
+ }
55
+
56
+ return group;
57
+ }
58
+
59
+ /*
60
+ * Wires up the reads the hooks make: findOneById resolves a parent, findBy
61
+ * resolves either "every group on the status page" or "the groups this update
62
+ * matches", and the order bookkeeping is stubbed out so these cases only
63
+ * exercise the hierarchy rules.
64
+ */
65
+ function mockService(data: {
66
+ groupsOnStatusPage: Array<StatusPageGroup>;
67
+ groupsMatchedByUpdate?: Array<StatusPageGroup> | undefined;
68
+ }): void {
69
+ jest
70
+ .spyOn(StatusPageGroupService, "findOneById")
71
+ .mockImplementation(async (findBy: any) => {
72
+ return (
73
+ data.groupsOnStatusPage.find((group: StatusPageGroup) => {
74
+ return group._id?.toString() === findBy.id?.toString();
75
+ }) || null
76
+ );
77
+ });
78
+
79
+ jest
80
+ .spyOn(StatusPageGroupService, "findBy")
81
+ .mockImplementation(async (findBy: any) => {
82
+ if (findBy.query && findBy.query.statusPageId) {
83
+ return data.groupsOnStatusPage;
84
+ }
85
+
86
+ return data.groupsMatchedByUpdate || [];
87
+ });
88
+
89
+ jest
90
+ .spyOn(StatusPageGroupService, "countBy")
91
+ .mockResolvedValue(new PositiveNumber(data.groupsOnStatusPage.length));
92
+
93
+ jest.spyOn(StatusPageGroupService, "updateOneBy").mockResolvedValue(1);
94
+ }
95
+
96
+ function createBy(data: {
97
+ parentStatusPageGroupId?: ObjectID | undefined;
98
+ statusPageId?: ObjectID | undefined;
99
+ }): CreateBy<StatusPageGroup> {
100
+ const group: StatusPageGroup = new StatusPageGroup();
101
+ group.name = "New Group";
102
+ group.projectId = PROJECT_ID;
103
+ group.statusPageId = data.statusPageId || STATUS_PAGE_ID;
104
+ group.order = 1;
105
+
106
+ if (data.parentStatusPageGroupId) {
107
+ group.parentStatusPageGroupId = data.parentStatusPageGroupId;
108
+ }
109
+
110
+ return {
111
+ data: group,
112
+ props: { isRoot: true },
113
+ } as CreateBy<StatusPageGroup>;
114
+ }
115
+
116
+ function updateBy(data: {
117
+ id: ObjectID;
118
+ parentStatusPageGroupId: ObjectID | null;
119
+ }): UpdateBy<StatusPageGroup> {
120
+ return {
121
+ query: { _id: data.id.toString() },
122
+ data: {
123
+ parentStatusPageGroupId: data.parentStatusPageGroupId,
124
+ },
125
+ props: { isRoot: true },
126
+ } as unknown as UpdateBy<StatusPageGroup>;
127
+ }
128
+
129
+ describe("StatusPageGroupService nesting rules", () => {
130
+ afterEach(() => {
131
+ jest.restoreAllMocks();
132
+ });
133
+
134
+ describe("on create", () => {
135
+ it("accepts a parent that lives on the same status page", async () => {
136
+ const parent: StatusPageGroup = makeGroup({ id: groupId(1) });
137
+ mockService({ groupsOnStatusPage: [parent] });
138
+
139
+ await expect(
140
+ (StatusPageGroupService as any).onBeforeCreate(
141
+ createBy({ parentStatusPageGroupId: groupId(1) }),
142
+ ),
143
+ ).resolves.toBeDefined();
144
+ });
145
+
146
+ it("rejects a parent that does not exist", async () => {
147
+ mockService({ groupsOnStatusPage: [] });
148
+
149
+ await expect(
150
+ (StatusPageGroupService as any).onBeforeCreate(
151
+ createBy({ parentStatusPageGroupId: groupId(1) }),
152
+ ),
153
+ ).rejects.toThrow(new BadDataException("Parent group not found."));
154
+ });
155
+
156
+ it("rejects a parent from another status page", async () => {
157
+ const parent: StatusPageGroup = makeGroup({
158
+ id: groupId(1),
159
+ statusPageId: OTHER_STATUS_PAGE_ID,
160
+ });
161
+ mockService({ groupsOnStatusPage: [parent] });
162
+
163
+ await expect(
164
+ (StatusPageGroupService as any).onBeforeCreate(
165
+ createBy({ parentStatusPageGroupId: groupId(1) }),
166
+ ),
167
+ ).rejects.toThrow(
168
+ new BadDataException(
169
+ "Parent group must belong to the same status page.",
170
+ ),
171
+ );
172
+ });
173
+
174
+ it("rejects a parent that is already at the nesting limit", async () => {
175
+ // a chain 0 -> 1 -> ... -> 9, so group 9 already sits at the deepest level.
176
+ const chain: Array<StatusPageGroup> = [];
177
+
178
+ for (
179
+ let index: number = 0;
180
+ index < StatusPageGroupTreeUtil.MaxNestingDepth;
181
+ index++
182
+ ) {
183
+ chain.push(
184
+ makeGroup({
185
+ id: groupId(index),
186
+ parentId: index === 0 ? undefined : groupId(index - 1),
187
+ }),
188
+ );
189
+ }
190
+
191
+ mockService({ groupsOnStatusPage: chain });
192
+
193
+ await expect(
194
+ (StatusPageGroupService as any).onBeforeCreate(
195
+ createBy({
196
+ parentStatusPageGroupId: groupId(
197
+ StatusPageGroupTreeUtil.MaxNestingDepth - 1,
198
+ ),
199
+ }),
200
+ ),
201
+ ).rejects.toThrow(BadDataException);
202
+
203
+ // one level up is still fine.
204
+ await expect(
205
+ (StatusPageGroupService as any).onBeforeCreate(
206
+ createBy({
207
+ parentStatusPageGroupId: groupId(
208
+ StatusPageGroupTreeUtil.MaxNestingDepth - 2,
209
+ ),
210
+ }),
211
+ ),
212
+ ).resolves.toBeDefined();
213
+ });
214
+
215
+ it("does not look for a parent when none was supplied", async () => {
216
+ mockService({ groupsOnStatusPage: [] });
217
+
218
+ await expect(
219
+ (StatusPageGroupService as any).onBeforeCreate(createBy({})),
220
+ ).resolves.toBeDefined();
221
+
222
+ expect(StatusPageGroupService.findOneById).not.toHaveBeenCalled();
223
+ });
224
+ });
225
+
226
+ describe("on update", () => {
227
+ it("accepts a move to another branch", async () => {
228
+ const branchA: StatusPageGroup = makeGroup({ id: groupId(1) });
229
+ const branchB: StatusPageGroup = makeGroup({ id: groupId(2) });
230
+ const moving: StatusPageGroup = makeGroup({
231
+ id: groupId(3),
232
+ parentId: groupId(1),
233
+ });
234
+
235
+ mockService({
236
+ groupsOnStatusPage: [branchA, branchB, moving],
237
+ groupsMatchedByUpdate: [moving],
238
+ });
239
+
240
+ await expect(
241
+ (StatusPageGroupService as any).onBeforeUpdate(
242
+ updateBy({ id: groupId(3), parentStatusPageGroupId: groupId(2) }),
243
+ ),
244
+ ).resolves.toBeDefined();
245
+ });
246
+
247
+ it("rejects a group being made its own parent", async () => {
248
+ const group: StatusPageGroup = makeGroup({ id: groupId(1) });
249
+
250
+ mockService({
251
+ groupsOnStatusPage: [group],
252
+ groupsMatchedByUpdate: [group],
253
+ });
254
+
255
+ await expect(
256
+ (StatusPageGroupService as any).onBeforeUpdate(
257
+ updateBy({ id: groupId(1), parentStatusPageGroupId: groupId(1) }),
258
+ ),
259
+ ).rejects.toThrow(
260
+ new BadDataException("A group cannot be its own parent group."),
261
+ );
262
+ });
263
+
264
+ it("rejects a group being nested under its own child", async () => {
265
+ const parent: StatusPageGroup = makeGroup({ id: groupId(1) });
266
+ const child: StatusPageGroup = makeGroup({
267
+ id: groupId(2),
268
+ parentId: groupId(1),
269
+ });
270
+
271
+ mockService({
272
+ groupsOnStatusPage: [parent, child],
273
+ groupsMatchedByUpdate: [parent],
274
+ });
275
+
276
+ await expect(
277
+ (StatusPageGroupService as any).onBeforeUpdate(
278
+ updateBy({ id: groupId(1), parentStatusPageGroupId: groupId(2) }),
279
+ ),
280
+ ).rejects.toThrow(
281
+ new BadDataException(
282
+ "This group cannot be nested under one of its own sub groups.",
283
+ ),
284
+ );
285
+ });
286
+
287
+ it("rejects a group being nested under a deeper descendant", async () => {
288
+ const grandparent: StatusPageGroup = makeGroup({ id: groupId(1) });
289
+ const parent: StatusPageGroup = makeGroup({
290
+ id: groupId(2),
291
+ parentId: groupId(1),
292
+ });
293
+ const child: StatusPageGroup = makeGroup({
294
+ id: groupId(3),
295
+ parentId: groupId(2),
296
+ });
297
+
298
+ mockService({
299
+ groupsOnStatusPage: [grandparent, parent, child],
300
+ groupsMatchedByUpdate: [grandparent],
301
+ });
302
+
303
+ await expect(
304
+ (StatusPageGroupService as any).onBeforeUpdate(
305
+ updateBy({ id: groupId(1), parentStatusPageGroupId: groupId(3) }),
306
+ ),
307
+ ).rejects.toThrow(
308
+ new BadDataException(
309
+ "This group cannot be nested under one of its own sub groups.",
310
+ ),
311
+ );
312
+ });
313
+
314
+ /*
315
+ * Moving a group drags its whole subtree with it, so the limit has to be
316
+ * checked against the deepest descendant, not just the group itself.
317
+ */
318
+ it("rejects a move that would push the group's own subtree past the limit", async () => {
319
+ const chain: Array<StatusPageGroup> = [];
320
+
321
+ for (
322
+ let index: number = 0;
323
+ index < StatusPageGroupTreeUtil.MaxNestingDepth - 1;
324
+ index++
325
+ ) {
326
+ chain.push(
327
+ makeGroup({
328
+ id: groupId(index),
329
+ parentId: index === 0 ? undefined : groupId(index - 1),
330
+ }),
331
+ );
332
+ }
333
+
334
+ // a separate two level branch: 100 -> 101.
335
+ const movingRoot: StatusPageGroup = makeGroup({ id: groupId(100) });
336
+ const movingChild: StatusPageGroup = makeGroup({
337
+ id: groupId(101),
338
+ parentId: groupId(100),
339
+ });
340
+
341
+ mockService({
342
+ groupsOnStatusPage: [...chain, movingRoot, movingChild],
343
+ groupsMatchedByUpdate: [movingRoot],
344
+ });
345
+
346
+ await expect(
347
+ (StatusPageGroupService as any).onBeforeUpdate(
348
+ updateBy({
349
+ id: groupId(100),
350
+ parentStatusPageGroupId: groupId(
351
+ StatusPageGroupTreeUtil.MaxNestingDepth - 2,
352
+ ),
353
+ }),
354
+ ),
355
+ ).rejects.toThrow(BadDataException);
356
+ });
357
+
358
+ it("does not validate a parent when the update detaches the group", async () => {
359
+ const group: StatusPageGroup = makeGroup({
360
+ id: groupId(1),
361
+ parentId: groupId(2),
362
+ });
363
+
364
+ mockService({
365
+ groupsOnStatusPage: [group],
366
+ groupsMatchedByUpdate: [group],
367
+ });
368
+
369
+ await expect(
370
+ (StatusPageGroupService as any).onBeforeUpdate(
371
+ updateBy({ id: groupId(1), parentStatusPageGroupId: null }),
372
+ ),
373
+ ).resolves.toBeDefined();
374
+
375
+ expect(StatusPageGroupService.findOneById).not.toHaveBeenCalled();
376
+ });
377
+
378
+ it("does not read anything when the update does not touch the parent", async () => {
379
+ mockService({ groupsOnStatusPage: [] });
380
+
381
+ const update: UpdateBy<StatusPageGroup> = {
382
+ query: { _id: groupId(1).toString() },
383
+ data: { name: "Renamed" },
384
+ props: { isRoot: true },
385
+ } as unknown as UpdateBy<StatusPageGroup>;
386
+
387
+ await expect(
388
+ (StatusPageGroupService as any).onBeforeUpdate(update),
389
+ ).resolves.toBeDefined();
390
+
391
+ expect(StatusPageGroupService.findOneById).not.toHaveBeenCalled();
392
+ expect(StatusPageGroupService.findBy).not.toHaveBeenCalled();
393
+ });
394
+ });
395
+ });
@@ -58,29 +58,34 @@ const getStripeCustomer: GetStripeCustomerFunction = (
58
58
  };
59
59
  };
60
60
 
61
- type GetStripeSubscriptionFunction = () => Stripe.Subscription;
62
-
63
- const getStripeSubscription: GetStripeSubscriptionFunction =
64
- (): Stripe.Subscription => {
65
- return {
66
- id: Faker.generateRandomObjectID().toString(),
67
- items: {
68
- data: [
69
- {
70
- id: Faker.generateRandomObjectID().toString(),
71
- // @ts-expect-error - Simplified mock price object for testing without all required Stripe Price properties
72
- price: {
73
- id: new BillingService().getMeteredPlanPriceId(
74
- ProductType.ActiveMonitoring,
75
- ),
76
- },
61
+ type GetStripeSubscriptionFunction = (options?: {
62
+ id?: string | undefined;
63
+ status?: Stripe.Subscription.Status | undefined;
64
+ }) => Stripe.Subscription;
65
+
66
+ const getStripeSubscription: GetStripeSubscriptionFunction = (options?: {
67
+ id?: string | undefined;
68
+ status?: Stripe.Subscription.Status | undefined;
69
+ }): Stripe.Subscription => {
70
+ return {
71
+ id: options?.id || Faker.generateRandomObjectID().toString(),
72
+ items: {
73
+ data: [
74
+ {
75
+ id: Faker.generateRandomObjectID().toString(),
76
+ // @ts-expect-error - Simplified mock price object for testing without all required Stripe Price properties
77
+ price: {
78
+ id: new BillingService().getMeteredPlanPriceId(
79
+ ProductType.ActiveMonitoring,
80
+ ),
77
81
  },
78
- ],
79
- },
80
- status: "active",
81
- customer: getStripeCustomer(),
82
- };
82
+ },
83
+ ],
84
+ },
85
+ status: options?.status || "active",
86
+ customer: getStripeCustomer(),
83
87
  };
88
+ };
84
89
 
85
90
  type GetSubscriptionPlanDataFunction = () => SubscriptionPlan;
86
91
 
@@ -0,0 +1,227 @@
1
+ import DatabaseRequestType from "../../../../../Server/Types/BaseDatabase/DatabaseRequestType";
2
+ import ColumnPermissions from "../../../../../Server/Types/Database/Permissions/ColumnPermission";
3
+ import WorkflowVariable from "../../../../../Models/DatabaseModels/WorkflowVariable";
4
+ import DatabaseCommonInteractionProps from "../../../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
5
+ import Columns from "../../../../../Types/Database/Columns";
6
+ import BadDataException from "../../../../../Types/Exception/BadDataException";
7
+ import ObjectID from "../../../../../Types/ObjectID";
8
+ import Permission, {
9
+ UserPermission,
10
+ UserTenantAccessPermission,
11
+ } from "../../../../../Types/Permission";
12
+ import { describe, expect, it } from "@jest/globals";
13
+
14
+ /*
15
+ * A customer's Workflow could not rotate the secret it stored in a Workflow
16
+ * Variable. The API key carried Permission.EditWorkflowVariable - which is the
17
+ * table-level update grant on WorkflowVariable - but the "content" column's
18
+ * ColumnAccessControl.update listed only ProjectOwner and ProjectAdmin. So the
19
+ * one column the caller actually wanted to write was the one column its
20
+ * permission did not cover.
21
+ *
22
+ * "content" is the secret itself, so its read list is deliberately empty: not
23
+ * even a ProjectOwner may read it back. Widening update must not widen read -
24
+ * ColumnAccessControl keeps create/read/update as three independent arrays, and
25
+ * these tests pin that independence so a future edit cannot quietly turn a
26
+ * write grant into a way to exfiltrate the secret.
27
+ */
28
+
29
+ const projectId: ObjectID = ObjectID.generate();
30
+ const userId: ObjectID = ObjectID.generate();
31
+
32
+ /*
33
+ * DatabaseCommonInteractionPropsUtil.getUserPermissions drops every permission
34
+ * whose isBlockPermission does not match the requested PermissionType, and it
35
+ * only reads the tenant bucket when props.tenantId is set. Getting either wrong
36
+ * yields an empty permission set, which would make the "does not throw" cases
37
+ * below pass for entirely the wrong reason. Every permission built here is an
38
+ * explicit allow, keyed under the tenant this request runs as.
39
+ */
40
+ function makeProps(
41
+ permissions: Array<Permission>,
42
+ ): DatabaseCommonInteractionProps {
43
+ const tenantPermission: UserTenantAccessPermission = {
44
+ projectId,
45
+ _type: "UserTenantAccessPermission",
46
+ permissions: permissions.map((permission: Permission) => {
47
+ return {
48
+ _type: "UserPermission",
49
+ permission: permission,
50
+ labelIds: [],
51
+ isBlockPermission: false,
52
+ };
53
+ }),
54
+ };
55
+
56
+ return {
57
+ userId,
58
+ tenantId: projectId,
59
+ userTenantAccessPermission: {
60
+ [projectId.toString()]: tenantPermission,
61
+ },
62
+ };
63
+ }
64
+
65
+ function makeUserPermissions(
66
+ permissions: Array<Permission>,
67
+ ): Array<UserPermission> {
68
+ return permissions.map((permission: Permission) => {
69
+ return {
70
+ _type: "UserPermission",
71
+ permission: permission,
72
+ labelIds: [],
73
+ isBlockPermission: false,
74
+ };
75
+ });
76
+ }
77
+
78
+ type CheckFunction = () => void;
79
+
80
+ function checkUpdate(
81
+ data: Partial<WorkflowVariable>,
82
+ permissions: Array<Permission>,
83
+ ): CheckFunction {
84
+ return () => {
85
+ ColumnPermissions.checkDataColumnPermissions(
86
+ WorkflowVariable,
87
+ data as WorkflowVariable,
88
+ makeProps(permissions),
89
+ DatabaseRequestType.Update,
90
+ );
91
+ };
92
+ }
93
+
94
+ describe("ColumnPermissions on WorkflowVariable", () => {
95
+ describe("harness guard", () => {
96
+ /*
97
+ * Runs first on purpose. Every other update assertion in this file is a
98
+ * "does not throw", which an empty or mis-shaped permission set would also
99
+ * satisfy - getModelColumnsByPermissions would return no columns, but so
100
+ * would a props object the util silently ignored. This case has a caller
101
+ * that genuinely lacks the update grant, so it MUST throw. If it stops
102
+ * throwing, the props factory above is broken, not the model.
103
+ */
104
+ it("still refuses a read-only key that tries to write content", () => {
105
+ expect(
106
+ checkUpdate({ content: "rotated-token" }, [
107
+ Permission.ReadWorkflowVariable,
108
+ ]),
109
+ ).toThrow(BadDataException);
110
+
111
+ expect(
112
+ checkUpdate({ content: "rotated-token" }, [
113
+ Permission.ReadWorkflowVariable,
114
+ ]),
115
+ ).toThrow(
116
+ "User is not allowed to update on content column of Workflow Variable",
117
+ );
118
+ });
119
+ });
120
+
121
+ describe("update", () => {
122
+ /*
123
+ * The fix. EditWorkflowVariable is the table-level update grant, so a key
124
+ * holding it was already allowed to reach the update path - it just could
125
+ * not write the only column worth writing.
126
+ */
127
+ it("lets a key with EditWorkflowVariable write the content column", () => {
128
+ expect(
129
+ checkUpdate({ content: "rotated-token" }, [
130
+ Permission.EditWorkflowVariable,
131
+ ]),
132
+ ).not.toThrow();
133
+ });
134
+
135
+ it("still lets a key with EditWorkflowVariable write name and description", () => {
136
+ expect(
137
+ checkUpdate({ name: "Airflow-Token" }, [
138
+ Permission.EditWorkflowVariable,
139
+ ]),
140
+ ).not.toThrow();
141
+
142
+ expect(
143
+ checkUpdate({ description: "Token used by the Airflow workflow" }, [
144
+ Permission.EditWorkflowVariable,
145
+ ]),
146
+ ).not.toThrow();
147
+ });
148
+
149
+ it("still lets a project admin write the content column", () => {
150
+ expect(
151
+ checkUpdate({ content: "rotated-token" }, [Permission.ProjectAdmin]),
152
+ ).not.toThrow();
153
+ });
154
+
155
+ it("still lets a project owner write the content column", () => {
156
+ expect(
157
+ checkUpdate({ content: "rotated-token" }, [Permission.ProjectOwner]),
158
+ ).not.toThrow();
159
+ });
160
+ });
161
+
162
+ describe("create", () => {
163
+ /*
164
+ * The create list already carried CreateWorkflowVariable, so a variable
165
+ * could always be created with its content and then never edited. Pinned
166
+ * here so the update widening is not mistaken for having changed create.
167
+ */
168
+ it("leaves the create path alone for CreateWorkflowVariable", () => {
169
+ expect(() => {
170
+ ColumnPermissions.checkDataColumnPermissions(
171
+ WorkflowVariable,
172
+ {
173
+ content: "initial-token",
174
+ name: "Airflow-Token",
175
+ } as WorkflowVariable,
176
+ makeProps([Permission.CreateWorkflowVariable]),
177
+ DatabaseRequestType.Create,
178
+ );
179
+ }).not.toThrow();
180
+ });
181
+ });
182
+
183
+ describe("read", () => {
184
+ /*
185
+ * content.read is [] - the secret is write-only by design, and the UI reads
186
+ * it back through nothing. Asserting "name" is present in the same call
187
+ * proves the read list was genuinely evaluated rather than the whole model
188
+ * coming back empty, which would make the content assertion vacuous.
189
+ */
190
+ it("keeps content unreadable even for a project owner", () => {
191
+ const columns: Columns = ColumnPermissions.getModelColumnsByPermissions(
192
+ WorkflowVariable,
193
+ makeUserPermissions([
194
+ Permission.ProjectOwner,
195
+ Permission.ReadWorkflowVariable,
196
+ ]),
197
+ DatabaseRequestType.Read,
198
+ );
199
+
200
+ expect(columns.columns).not.toContain("content");
201
+ expect(columns.columns).toContain("name");
202
+ });
203
+
204
+ it("reports content as updatable but not readable for the same key", () => {
205
+ const userPermissions: Array<UserPermission> = makeUserPermissions([
206
+ Permission.EditWorkflowVariable,
207
+ ]);
208
+
209
+ const updatableColumns: Columns =
210
+ ColumnPermissions.getModelColumnsByPermissions(
211
+ WorkflowVariable,
212
+ userPermissions,
213
+ DatabaseRequestType.Update,
214
+ );
215
+
216
+ const readableColumns: Columns =
217
+ ColumnPermissions.getModelColumnsByPermissions(
218
+ WorkflowVariable,
219
+ userPermissions,
220
+ DatabaseRequestType.Read,
221
+ );
222
+
223
+ expect(updatableColumns.columns).toContain("content");
224
+ expect(readableColumns.columns).not.toContain("content");
225
+ });
226
+ });
227
+ });