@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.
- package/Models/AnalyticsModels/KubernetesCostAllocation.ts +103 -0
- package/Models/DatabaseModels/AlertEpisodeStateTimeline.ts +1 -0
- package/Models/DatabaseModels/AlertStateTimeline.ts +1 -0
- package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
- package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
- package/Models/DatabaseModels/Index.ts +5 -0
- package/Models/DatabaseModels/LogDropFilter.ts +89 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +13 -3
- package/Models/DatabaseModels/RecommendationDismissal.ts +463 -0
- package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
- package/Models/DatabaseModels/StatusPageGroup.ts +95 -0
- package/Models/DatabaseModels/TableView.ts +40 -0
- package/Models/DatabaseModels/TraceDropFilter.ts +89 -0
- package/Models/DatabaseModels/WorkflowVariable.ts +5 -1
- package/Server/API/AlertAPI.ts +32 -17
- package/Server/API/BaseAPI.ts +31 -2
- package/Server/API/BaseAnalyticsAPI.ts +36 -2
- package/Server/API/CommonAPI.ts +57 -0
- package/Server/API/IncidentAPI.ts +60 -33
- package/Server/API/IncidentEpisodeAPI.ts +31 -16
- package/Server/API/MonitorAPI.ts +30 -0
- package/Server/API/MonitorTemplateAPI.ts +8 -0
- package/Server/API/ProbeAPI.ts +196 -15
- package/Server/API/ProjectAPI.ts +79 -1
- package/Server/API/ScheduledMaintenanceAPI.ts +33 -18
- package/Server/API/StatusPageAPI.ts +74 -37
- package/Server/API/WorkspaceNotificationRuleAPI.ts +34 -4
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.ts +13 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.ts +527 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.ts +55 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.ts +53 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Services/AlertEpisodeService.ts +47 -0
- package/Server/Services/AlertService.ts +125 -0
- package/Server/Services/BillingService.ts +98 -0
- package/Server/Services/DatabaseService.ts +184 -20
- package/Server/Services/IncidentEpisodeService.ts +47 -0
- package/Server/Services/IncidentService.ts +123 -0
- package/Server/Services/IncidentTemplateService.ts +123 -1
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/LogDropFilterService.ts +133 -0
- package/Server/Services/MonitorProbeService.ts +94 -4
- package/Server/Services/MonitorService.ts +48 -43
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +70 -0
- package/Server/Services/ProbeService.ts +66 -0
- package/Server/Services/ProjectService.ts +131 -7
- package/Server/Services/RecommendationDismissalService.ts +52 -0
- package/Server/Services/RunbookAgentJobService.ts +68 -7
- package/Server/Services/ScheduledMaintenanceService.ts +103 -0
- package/Server/Services/ScheduledMaintenanceTemplateService.ts +90 -0
- package/Server/Services/StatusPageGroupService.ts +186 -0
- package/Server/Services/TraceDropFilterService.ts +133 -0
- package/Server/Types/Workflow/Components/API/Delete.ts +12 -0
- package/Server/Types/Workflow/Components/API/Get.ts +12 -0
- package/Server/Types/Workflow/Components/API/Patch.ts +12 -0
- package/Server/Types/Workflow/Components/API/Post.ts +12 -0
- package/Server/Types/Workflow/Components/API/Put.ts +13 -0
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +212 -0
- package/Server/Utils/DropFilterValidation.ts +127 -0
- package/Server/Utils/Errors.ts +5 -0
- package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
- package/Server/Utils/Monitor/MonitorIncident.ts +31 -2
- package/Server/Utils/Telemetry/AppMetrics.ts +31 -0
- package/Tests/Models/AnalyticsModels/KubernetesCostAllocation.test.ts +16 -0
- package/Tests/Models/DatabaseModels/MonitorProbeColumnAccessControl.test.ts +196 -0
- package/Tests/Models/RecommendationDismissalModel.test.ts +269 -0
- package/Tests/Server/API/BaseAPIUpdatePayloadValidation.test.ts +320 -0
- package/Tests/Server/API/BaseAnalyticsAPIUpdatePayloadValidation.test.ts +293 -0
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +164 -0
- package/Tests/Server/API/ProbeAPI.test.ts +422 -53
- package/Tests/Server/API/ProjectAPI.test.ts +180 -0
- package/Tests/Server/API/ProjectAPIExtendTrialBillingDisabled.test.ts +138 -0
- package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +458 -0
- package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +359 -0
- package/Tests/Server/Infrastructure/ProcessSignalDelivery.test.ts +427 -0
- package/Tests/Server/Services/BillingServiceExtendTrial.test.ts +439 -0
- package/Tests/Server/Services/CrossProjectReferenceWriteGuard.test.ts +810 -0
- package/Tests/Server/Services/DatabaseServiceAtomicAddToColumns.test.ts +269 -0
- package/Tests/Server/Services/DatabaseServiceEmptyUpdate.test.ts +277 -0
- package/Tests/Server/Services/DatabaseServiceSortColumnSelect.test.ts +201 -0
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +81 -23
- package/Tests/Server/Services/DropFilterSaveValidation.test.ts +398 -0
- package/Tests/Server/Services/MonitorProbeDeleteHooks.test.ts +280 -0
- package/Tests/Server/Services/MonitorProbeServiceProbeTenancy.test.ts +304 -0
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +262 -0
- package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +614 -0
- package/Tests/Server/Services/RecommendationDismissalService.test.ts +306 -0
- package/Tests/Server/Services/RepairCrossProjectIncidentReferencesMigration.test.ts +528 -0
- package/Tests/Server/Services/StatusPageGroupNesting.test.ts +395 -0
- package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +26 -21
- package/Tests/Server/Types/Database/Permissions/WorkflowVariableColumnPermission.test.ts +227 -0
- package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +285 -0
- package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +463 -0
- package/Tests/Server/Utils/DropFilterValidation.test.ts +269 -0
- package/Tests/Server/Utils/Telemetry/SpanUtil.test.ts +94 -0
- package/Tests/Types/DateUserTimezone.test.ts +52 -0
- package/Tests/Types/JSONFunctions.test.ts +103 -1
- package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +177 -9
- package/Tests/Types/Monitor/MonitorStepDnsMonitor.test.ts +105 -0
- package/Tests/Types/Monitor/MonitorStepDnssecMonitor.test.ts +131 -0
- package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +60 -0
- package/Tests/Types/Monitor/MonitorStepExternalStatusPageMonitor.test.ts +82 -0
- package/Tests/Types/Monitor/MonitorStepInfrastructureMonitors.test.ts +268 -0
- package/Tests/Types/Monitor/MonitorStepMetricMonitor.test.ts +386 -0
- package/Tests/Types/Monitor/MonitorStepProfileMonitor.test.ts +185 -0
- package/Tests/Types/Monitor/MonitorStepSnmpMonitor.test.ts +156 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +371 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +901 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +607 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +754 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +960 -0
- package/Tests/Types/RollingTime/RollingTimeUtil.test.ts +186 -0
- package/Tests/Types/Runbook/RunbookStepTimeout.test.ts +410 -0
- package/Tests/Types/Telemetry/DropFilterSampling.test.ts +241 -0
- package/Tests/Types/Workspace/NotificationRuleConditionUtil.test.ts +353 -0
- package/Tests/Types/Workspace/NotificationRuleUtil.test.ts +566 -0
- package/Tests/UI/Components/CodeEditor.test.tsx +174 -0
- package/Tests/UI/Components/ErrorBoundary.test.tsx +555 -24
- package/Tests/UI/Components/InfoCard.test.tsx +358 -0
- package/Tests/UI/Components/LogTimeRangePicker.test.tsx +138 -0
- package/Tests/UI/Components/Modal.test.tsx +43 -5
- package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +679 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +397 -0
- package/Tests/UI/Components/ModelTable/ColumnCustomizationModal.test.tsx +999 -0
- package/Tests/UI/Components/ModelTable/ColumnPreference.test.ts +1678 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +1094 -0
- package/Tests/UI/Components/Runbook/StepTimeoutInput.test.tsx +386 -0
- package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +671 -0
- package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +404 -0
- package/Tests/UI/Utils/DropdownAlignment.test.ts +306 -0
- package/Tests/UI/Utils/TableFilterUrlState.test.ts +292 -0
- package/Tests/Utils/Monitor/MonitorSummaryProbeUtil.test.ts +263 -0
- package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +583 -0
- package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +1072 -0
- package/Tests/Utils/StatusPage/GroupTree.test.ts +583 -0
- package/Tests/Utils/StatusPage/ResourceUptime.test.ts +411 -0
- package/Tests/Utils/UserPreferences.test.ts +563 -0
- package/Types/Date.ts +15 -6
- package/Types/JSONFunctions.ts +7 -2
- package/Types/Kubernetes/KubernetesCostIngest.ts +37 -1
- package/Types/Monitor/KubernetesAlertTemplates.ts +205 -0
- package/Types/Monitor/MonitorStep.ts +10 -1
- package/Types/Monitor/MonitorStepMetricMonitor.ts +46 -1
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +413 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +168 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +175 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +743 -0
- package/Types/Permission.ts +45 -0
- package/Types/Recommendation/RecommendationType.ts +20 -0
- package/Types/Runbook/RunbookExecutionDeadline.ts +129 -0
- package/Types/Runbook/RunbookStepTimeout.ts +202 -0
- package/Types/Telemetry/DropFilterSampling.ts +92 -0
- package/UI/Components/AI/GenerateFromAIModal.tsx +0 -2
- package/UI/Components/Accordion/Accordion.tsx +10 -2
- package/UI/Components/BulkUpdate/BulkLabelActions.tsx +0 -1
- package/UI/Components/CodeEditor/CodeEditor.tsx +34 -20
- package/UI/Components/Date/RangeStartAndEndDateView.tsx +0 -1
- package/UI/Components/EditionLabel/EditionLabel.tsx +1 -27
- package/UI/Components/Error/PageError.tsx +0 -4
- package/UI/Components/ErrorBoundary.tsx +252 -15
- package/UI/Components/InfoCard/InfoCard.tsx +58 -1
- package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +34 -1
- package/UI/Components/MasterPage/MasterPage.tsx +65 -0
- package/UI/Components/Modal/Modal.tsx +16 -60
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +0 -8
- package/UI/Components/ModelTable/BaseModelTable.tsx +503 -71
- package/UI/Components/ModelTable/Column.ts +17 -0
- package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +523 -0
- package/UI/Components/ModelTable/ColumnPreference.ts +482 -0
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +326 -0
- package/UI/Components/ModelTable/TableView.tsx +24 -2
- package/UI/Components/ModelTable/useCustomFieldColumns.ts +150 -0
- package/UI/Components/Runbook/StepTimeoutInput.tsx +173 -0
- package/UI/Components/SideMenu/SideMenu.tsx +24 -4
- package/UI/Components/StatusPage/ResourceGroupSection.tsx +231 -0
- package/UI/Components/Table/Table.tsx +14 -1
- package/UI/Components/Table/TableRow.tsx +180 -175
- package/UI/Components/Table/Types/Column.ts +2 -0
- package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +34 -1
- package/UI/Utils/DropdownAlignment.ts +162 -0
- package/UI/Utils/TableFilterUrlState.ts +59 -20
- package/Utils/API.ts +106 -2
- package/Utils/Monitor/MonitorSummaryProbeUtil.ts +130 -0
- package/Utils/NetworkDiscovery/ScanTargetUtil.ts +434 -0
- package/Utils/StatusPage/GroupNestingLayout.ts +343 -0
- package/Utils/StatusPage/GroupTree.ts +307 -0
- package/Utils/StatusPage/ResourceUptime.ts +90 -17
- package/Utils/UserPreferences.ts +53 -0
- package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js +86 -0
- package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LogDropFilter.js +91 -0
- package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +14 -4
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RecommendationDismissal.js +484 -0
- package/build/dist/Models/DatabaseModels/RecommendationDismissal.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageGroup.js +94 -0
- package/build/dist/Models/DatabaseModels/StatusPageGroup.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TableView.js +40 -0
- package/build/dist/Models/DatabaseModels/TableView.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js +91 -0
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js +5 -1
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
- package/build/dist/Server/API/AlertAPI.js +22 -13
- package/build/dist/Server/API/AlertAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +22 -1
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js +24 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +42 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +43 -26
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentEpisodeAPI.js +21 -12
- package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
- package/build/dist/Server/API/MonitorAPI.js +23 -0
- package/build/dist/Server/API/MonitorAPI.js.map +1 -1
- package/build/dist/Server/API/MonitorTemplateAPI.js +4 -0
- package/build/dist/Server/API/MonitorTemplateAPI.js.map +1 -1
- package/build/dist/Server/API/ProbeAPI.js +131 -15
- package/build/dist/Server/API/ProbeAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectAPI.js +62 -3
- package/build/dist/Server/API/ProjectAPI.js.map +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js +23 -14
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +61 -33
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js +26 -2
- package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js +397 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js +30 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeService.js +39 -0
- package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +95 -0
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +71 -0
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +140 -17
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +39 -0
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +100 -0
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +97 -0
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LogDropFilterService.js +93 -0
- package/build/dist/Server/Services/LogDropFilterService.js.map +1 -1
- package/build/dist/Server/Services/MonitorProbeService.js +73 -5
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +34 -39
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +71 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/ProbeService.js +64 -0
- package/build/dist/Server/Services/ProbeService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +103 -7
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RecommendationDismissalService.js +50 -0
- package/build/dist/Server/Services/RecommendationDismissalService.js.map +1 -0
- package/build/dist/Server/Services/RunbookAgentJobService.js +63 -5
- package/build/dist/Server/Services/RunbookAgentJobService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +83 -0
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +65 -0
- package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageGroupService.js +136 -0
- package/build/dist/Server/Services/StatusPageGroupService.js.map +1 -1
- package/build/dist/Server/Services/TraceDropFilterService.js +93 -0
- package/build/dist/Server/Services/TraceDropFilterService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Get.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Post.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Put.js +12 -0
- package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +132 -0
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -0
- package/build/dist/Server/Utils/DropFilterValidation.js +80 -0
- package/build/dist/Server/Utils/DropFilterValidation.js.map +1 -0
- package/build/dist/Server/Utils/Errors.js +3 -0
- package/build/dist/Server/Utils/Errors.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +30 -12
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +38 -18
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js +26 -0
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
- package/build/dist/Types/Date.js +14 -4
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/JSONFunctions.js +8 -3
- package/build/dist/Types/JSONFunctions.js.map +1 -1
- package/build/dist/Types/Kubernetes/KubernetesCostIngest.js.map +1 -1
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +192 -0
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +6 -1
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +32 -1
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +294 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +110 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +58 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +451 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -0
- package/build/dist/Types/Permission.js +40 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Recommendation/RecommendationType.js +21 -0
- package/build/dist/Types/Recommendation/RecommendationType.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookExecutionDeadline.js +93 -0
- package/build/dist/Types/Runbook/RunbookExecutionDeadline.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepTimeout.js +142 -0
- package/build/dist/Types/Runbook/RunbookStepTimeout.js.map +1 -0
- package/build/dist/Types/Telemetry/DropFilterSampling.js +75 -0
- package/build/dist/Types/Telemetry/DropFilterSampling.js.map +1 -0
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js +1 -2
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -1
- package/build/dist/UI/Components/Accordion/Accordion.js +9 -2
- package/build/dist/UI/Components/Accordion/Accordion.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +27 -14
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js +1 -1
- package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +2 -20
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/Error/PageError.js +1 -3
- package/build/dist/UI/Components/Error/PageError.js.map +1 -1
- package/build/dist/UI/Components/ErrorBoundary.js +145 -11
- package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.js +28 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +13 -2
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/MasterPage/MasterPage.js +50 -1
- package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +4 -32
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +308 -40
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +230 -0
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/ColumnPreference.js +258 -0
- package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +168 -0
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/TableView.js +13 -2
- package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +84 -0
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -0
- package/build/dist/UI/Components/Runbook/StepTimeoutInput.js +101 -0
- package/build/dist/UI/Components/Runbook/StepTimeoutInput.js.map +1 -0
- package/build/dist/UI/Components/SideMenu/SideMenu.js +15 -5
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +73 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -0
- package/build/dist/UI/Components/Table/Table.js +15 -2
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +11 -6
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +13 -2
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Utils/DropdownAlignment.js +98 -0
- package/build/dist/UI/Utils/DropdownAlignment.js.map +1 -0
- package/build/dist/UI/Utils/TableFilterUrlState.js +48 -15
- package/build/dist/UI/Utils/TableFilterUrlState.js.map +1 -1
- package/build/dist/Utils/API.js +39 -2
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js +97 -0
- package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +330 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -0
- package/build/dist/Utils/StatusPage/GroupNestingLayout.js +280 -0
- package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -0
- package/build/dist/Utils/StatusPage/GroupTree.js +214 -0
- package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceUptime.js +60 -16
- package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
- package/build/dist/Utils/UserPreferences.js +33 -0
- package/build/dist/Utils/UserPreferences.js.map +1 -1
- 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 = (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
81
|
-
|
|
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
|
+
});
|