@oneuptime/common 12.0.1 → 12.0.3
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/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +14 -0
- package/Models/DatabaseModels/Host.ts +12 -4
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/KubernetesContainer.ts +5 -4
- package/Models/DatabaseModels/KubernetesResource.ts +8 -7
- package/Models/DatabaseModels/LogDropFilter.ts +9 -20
- package/Models/DatabaseModels/PodmanResource.ts +6 -6
- package/Models/DatabaseModels/ServiceLevelObjective.ts +91 -0
- package/Models/DatabaseModels/StatusPage.ts +95 -0
- package/Models/DatabaseModels/StatusPageMonitorRule.ts +911 -0
- package/Models/DatabaseModels/StatusPageResource.ts +73 -0
- package/Models/DatabaseModels/TraceDropFilter.ts +9 -20
- package/Server/API/BaseAPI.ts +13 -2
- package/Server/API/DashboardAPI.ts +39 -0
- package/Server/API/TeamMemberAPI.ts +85 -0
- package/Server/EnvironmentConfig.ts +31 -1
- package/Server/Infrastructure/GlobalCache.ts +115 -0
- package/Server/Infrastructure/Postgres/DataSourceOptions.ts +16 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.ts +84 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.ts +40 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.ts +131 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts +123 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Middleware/ProjectAuthorization.ts +66 -4
- package/Server/Services/AlertStateTimelineService.ts +20 -0
- package/Server/Services/BillingService.ts +600 -51
- package/Server/Services/CephClusterService.ts +27 -45
- package/Server/Services/CephResourceService.ts +43 -4
- package/Server/Services/CloudResourceService.ts +24 -42
- package/Server/Services/DatabaseService.ts +198 -6
- package/Server/Services/DockerHostService.ts +20 -38
- package/Server/Services/DockerResourceService.ts +62 -8
- package/Server/Services/DockerSwarmClusterService.ts +28 -46
- package/Server/Services/DockerSwarmResourceService.ts +53 -4
- package/Server/Services/HostService.ts +47 -57
- package/Server/Services/IncidentStateTimelineService.ts +20 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/IoTDeviceService.ts +1 -17
- package/Server/Services/IoTFleetService.ts +20 -38
- package/Server/Services/KubernetesClusterService.ts +18 -36
- package/Server/Services/KubernetesContainerService.ts +50 -9
- package/Server/Services/KubernetesResourceService.ts +53 -7
- package/Server/Services/LabelService.ts +153 -1
- package/Server/Services/MetricTypeService.ts +84 -0
- package/Server/Services/MonitorService.ts +146 -14
- package/Server/Services/MonitorStatusTimelineService.ts +29 -0
- package/Server/Services/MonitorTemplateService.ts +65 -0
- package/Server/Services/PodmanHostService.ts +20 -38
- package/Server/Services/PodmanResourceService.ts +62 -8
- package/Server/Services/ProjectService.ts +165 -35
- package/Server/Services/ProxmoxClusterService.ts +24 -42
- package/Server/Services/ProxmoxResourceService.ts +43 -4
- package/Server/Services/RumApplicationService.ts +20 -38
- package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +21 -0
- package/Server/Services/ServerlessFunctionService.ts +25 -43
- package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +426 -0
- package/Server/Services/ServiceLevelObjectiveService.ts +39 -0
- package/Server/Services/ServiceService.ts +299 -73
- package/Server/Services/StatusPageMonitorRuleEngineService.ts +752 -0
- package/Server/Services/StatusPageMonitorRuleService.ts +471 -0
- package/Server/Services/StatusPageService.ts +95 -36
- package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +18 -1
- package/Server/Services/StatusPageSubscriberService.ts +3 -0
- package/Server/Services/TelemetryEntityRelationshipService.ts +1 -0
- package/Server/Services/TelemetryEntityService.ts +1 -0
- package/Server/Types/Database/JSONColumnQuery.ts +621 -0
- package/Server/Types/Database/Permissions/PublicPermission.ts +9 -2
- package/Server/Types/Database/QueryHelper.ts +17 -32
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +170 -39
- package/Server/Utils/Database/TruncateColumnValue.ts +84 -0
- package/Server/Utils/Monitor/MonitorResource.ts +63 -36
- package/Server/Utils/Monitor/MonitorStatusTimeline.ts +36 -0
- package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +148 -127
- package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +434 -0
- package/Server/Utils/SingleFlight.ts +83 -0
- package/Server/Utils/StatusPage/MonitorRulePatternValidator.ts +46 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +107 -26
- package/Server/Utils/Telemetry/ResourceHeartbeat.ts +314 -0
- package/Server/Utils/Telemetry/Telemetry.ts +351 -122
- package/Tests/App/Dashboard/UsersTableGroupsByPerson.test.tsx +448 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
- package/Tests/Models/DatabaseModels/ColumnTransformerInvariants.test.ts +306 -0
- package/Tests/Models/DatabaseModels/NumberColumnDeserialization.test.ts +333 -0
- package/Tests/Models/DatabaseModels/StatusPageMonitorRuleModel.test.ts +190 -0
- package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +704 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +26 -0
- package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +303 -0
- package/Tests/Server/Infrastructure/GlobalCache.test.ts +226 -0
- package/Tests/Server/Infrastructure/PostgresLockTimeoutOptions.test.ts +181 -0
- package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +350 -0
- package/Tests/Server/Middleware/ProjectAuthorizationApiKeyHeader.test.ts +362 -0
- package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +687 -0
- package/Tests/Server/Services/BillingService.test.ts +78 -3
- package/Tests/Server/Services/BillingServiceChangePlanCancel.test.ts +645 -0
- package/Tests/Server/Services/BillingServiceTrialPlanChange.test.ts +1005 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlocked.test.ts +342 -0
- package/Tests/Server/Services/DropFilterSaveValidation.test.ts +245 -0
- package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +503 -0
- package/Tests/Server/Services/HostIpAddressesColumnWidth.test.ts +198 -0
- package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +658 -0
- package/Tests/Server/Services/InventoryResourceNameColumnWidth.test.ts +500 -0
- package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +586 -0
- package/Tests/Server/Services/InventoryUpsertTruncationGuard.test.ts +1242 -0
- package/Tests/Server/Services/MetricTypeAttachServices.test.ts +222 -0
- package/Tests/Server/Services/MissingReferenceWriteGuard.test.ts +614 -0
- package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +23 -0
- package/Tests/Server/Services/ProjectServiceChangePlan.test.ts +650 -0
- package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +1 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +636 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +770 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +130 -0
- package/Tests/Server/Services/ServiceUpdateLastSeenSplitGates.test.ts +705 -0
- package/Tests/Server/Services/SloMonitorLabelRuleHooks.test.ts +352 -0
- package/Tests/Server/Services/StatusPageMonitorRuleEngineService.test.ts +1719 -0
- package/Tests/Server/Services/StatusPageMonitorRuleHooks.test.ts +1212 -0
- package/Tests/Server/Services/StatusPageMonitorRuleMonitorCreateHook.test.ts +228 -0
- package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +29 -13
- package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +69 -8
- package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +593 -0
- package/Tests/Server/Types/Database/Permissions/PublicPermission.test.ts +495 -0
- package/Tests/Server/Types/Database/QueryUtil.test.ts +113 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +267 -0
- package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +260 -13
- package/Tests/Server/Utils/Database/TruncateColumnValue.test.ts +179 -0
- package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +302 -0
- package/Tests/Server/Utils/MetricTypeIndexConvergence.test.ts +598 -0
- package/Tests/Server/Utils/Monitor/MonitorStatusTimelineUnusableStatus.test.ts +154 -0
- package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +638 -92
- package/Tests/Server/Utils/Monitor/MonitorStepsReferenceExtractor.test.ts +724 -0
- package/Tests/Server/Utils/SingleFlight.test.ts +221 -0
- package/Tests/Types/Dashboard/NetworkDashboardTemplate.test.ts +793 -0
- package/Tests/Types/Database/BigIntColumnTransformer.test.ts +147 -0
- package/Tests/Types/Database/DatabasePropertyTransformer.test.ts +140 -0
- package/Tests/Types/Database/NumericColumnValue.test.ts +127 -0
- package/Tests/Types/Decimal.test.ts +37 -0
- package/Tests/Types/Events/Recurring.test.ts +157 -0
- package/Tests/Types/Monitor/SnmpVersionParsing.test.ts +152 -0
- package/Tests/Types/Port.test.ts +38 -0
- package/Tests/UI/Components/LogsHistogram.test.tsx +276 -0
- package/Tests/UI/Components/ModelTable/ModelTableGroupsProjectUsers.test.tsx +375 -0
- package/Tests/UI/Components/ModelTable/useCustomFieldColumns.test.tsx +196 -0
- package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +489 -0
- package/Tests/UI/Components/UseLogsHistogram.test.tsx +500 -0
- package/Tests/UI/Utils/ProjectUsersModelAPI.test.ts +739 -0
- package/Tests/UI/Utils/TeamMembersByUser.test.ts +633 -0
- package/Tests/Utils/Dashboard/Components/DashboardComponentsUtil.test.ts +120 -0
- package/Tests/Utils/Dashboard/DashboardNetworkMapComponent.test.ts +327 -0
- package/Tests/Utils/StatusPage/ReportPeriod.test.ts +218 -0
- package/Tests/Utils/Telemetry/HostIpAddresses.test.ts +291 -0
- package/Types/CustomField/CustomFieldDefinition.ts +24 -0
- package/Types/Dashboard/DashboardComponentType.ts +1 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.ts +40 -0
- package/Types/Dashboard/DashboardTemplates.ts +397 -0
- package/Types/Database/BigIntColumnTransformer.ts +74 -0
- package/Types/Database/DatabaseProperty.ts +26 -0
- package/Types/Database/NumericColumnValue.ts +128 -0
- package/Types/Date.ts +112 -0
- package/Types/Decimal.ts +16 -4
- package/Types/Events/Recurring.ts +99 -1
- package/Types/Permission.ts +48 -0
- package/Types/Port.ts +16 -4
- package/Types/StatusPage/StatusPageReport.ts +11 -0
- package/Types/StatusPage/StatusPageReportPeriodType.ts +21 -0
- package/UI/Components/LogsViewer/useLiveLogsRefresh.ts +86 -0
- package/UI/Components/LogsViewer/useLogsHistogram.ts +113 -0
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +2 -6
- package/UI/Components/ModelTable/useCustomFieldColumns.ts +21 -2
- package/UI/Utils/ModelAPI/ProjectUsersModelAPI.ts +305 -0
- package/UI/Utils/TeamMembersByUser.ts +302 -0
- package/Utils/Dashboard/Components/DashboardNetworkMapComponent.ts +136 -0
- package/Utils/Dashboard/Components/Index.ts +7 -0
- package/Utils/StatusPage/ReportPeriod.ts +236 -0
- package/Utils/Telemetry/HostIpAddresses.ts +98 -0
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +12 -0
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Host.js +12 -4
- package/build/dist/Models/DatabaseModels/Host.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/KubernetesContainer.js +4 -4
- package/build/dist/Models/DatabaseModels/KubernetesContainer.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesResource.js +7 -7
- package/build/dist/Models/DatabaseModels/KubernetesResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LogDropFilter.js +9 -20
- package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/PodmanResource.js +6 -6
- package/build/dist/Models/DatabaseModels/PodmanResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js +87 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +98 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js +925 -0
- package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/StatusPageResource.js +72 -0
- package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js +9 -20
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +11 -1
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +39 -0
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/TeamMemberAPI.js +57 -2
- package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +27 -1
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/GlobalCache.js +91 -0
- package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +5 -3
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.js +45 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.js +31 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.js +90 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js +48 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.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/Middleware/ProjectAuthorization.js +59 -4
- package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
- package/build/dist/Server/Services/AlertStateTimelineService.js +19 -0
- package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +466 -36
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterService.js +26 -39
- package/build/dist/Server/Services/CephClusterService.js.map +1 -1
- package/build/dist/Server/Services/CephResourceService.js +28 -3
- package/build/dist/Server/Services/CephResourceService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceService.js +23 -36
- package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +155 -2
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostService.js +19 -32
- package/build/dist/Server/Services/DockerHostService.js.map +1 -1
- package/build/dist/Server/Services/DockerResourceService.js +34 -4
- package/build/dist/Server/Services/DockerResourceService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterService.js +27 -40
- package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmResourceService.js +28 -3
- package/build/dist/Server/Services/DockerSwarmResourceService.js.map +1 -1
- package/build/dist/Server/Services/HostService.js +58 -64
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.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/IoTDeviceService.js +1 -8
- package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetService.js +19 -32
- package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterService.js +17 -30
- package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesContainerService.js +29 -3
- package/build/dist/Server/Services/KubernetesContainerService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesResourceService.js +32 -4
- package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
- package/build/dist/Server/Services/LabelService.js +127 -0
- package/build/dist/Server/Services/LabelService.js.map +1 -1
- package/build/dist/Server/Services/MetricTypeService.js +74 -0
- package/build/dist/Server/Services/MetricTypeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +128 -9
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +28 -0
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +60 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostService.js +19 -32
- package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
- package/build/dist/Server/Services/PodmanResourceService.js +34 -4
- package/build/dist/Server/Services/PodmanResourceService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +135 -21
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterService.js +23 -36
- package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxResourceService.js +28 -3
- package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationService.js +19 -32
- package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +20 -0
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionService.js +24 -37
- package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +347 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js +33 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
- package/build/dist/Server/Services/ServiceService.js +236 -61
- package/build/dist/Server/Services/ServiceService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +603 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleService.js +401 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleService.js.map +1 -0
- package/build/dist/Server/Services/StatusPageService.js +69 -46
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +17 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +3 -0
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +1 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryEntityService.js +1 -0
- package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
- package/build/dist/Server/Types/Database/JSONColumnQuery.js +402 -0
- package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -0
- package/build/dist/Server/Types/Database/Permissions/PublicPermission.js +9 -2
- package/build/dist/Server/Types/Database/Permissions/PublicPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +17 -27
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +105 -29
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
- package/build/dist/Server/Utils/Database/TruncateColumnValue.js +32 -0
- package/build/dist/Server/Utils/Database/TruncateColumnValue.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +56 -32
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +30 -3
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +110 -98
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +312 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -0
- package/build/dist/Server/Utils/SingleFlight.js +76 -0
- package/build/dist/Server/Utils/SingleFlight.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +29 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +78 -19
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +160 -0
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +279 -104
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldDefinition.js +2 -0
- package/build/dist/Types/CustomField/CustomFieldDefinition.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +368 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Database/BigIntColumnTransformer.js +66 -0
- package/build/dist/Types/Database/BigIntColumnTransformer.js.map +1 -0
- package/build/dist/Types/Database/DatabaseProperty.js +25 -0
- package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
- package/build/dist/Types/Database/NumericColumnValue.js +97 -0
- package/build/dist/Types/Database/NumericColumnValue.js.map +1 -0
- package/build/dist/Types/Date.js +68 -0
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Decimal.js +14 -3
- package/build/dist/Types/Decimal.js.map +1 -1
- package/build/dist/Types/Events/Recurring.js +63 -0
- package/build/dist/Types/Events/Recurring.js.map +1 -1
- package/build/dist/Types/Permission.js +42 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Port.js +15 -5
- package/build/dist/Types/Port.js.map +1 -1
- package/build/dist/Types/StatusPage/StatusPageReportPeriodType.js +22 -0
- package/build/dist/Types/StatusPage/StatusPageReportPeriodType.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js +44 -0
- package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +75 -0
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +18 -2
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js +213 -0
- package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js.map +1 -0
- package/build/dist/UI/Utils/TeamMembersByUser.js +195 -0
- package/build/dist/UI/Utils/TeamMembersByUser.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js +114 -0
- package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/StatusPage/ReportPeriod.js +131 -0
- package/build/dist/Utils/StatusPage/ReportPeriod.js.map +1 -0
- package/build/dist/Utils/Telemetry/HostIpAddresses.js +82 -0
- package/build/dist/Utils/Telemetry/HostIpAddresses.js.map +1 -0
- package/jest.config.json +2 -0
- package/package.json +1 -1
- package/tsconfig.json +12 -1
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* The Postgres connection deadlines.
|
|
5
|
+
*
|
|
6
|
+
* `lock_timeout` was missing entirely, and its absence is what let the row-lock
|
|
7
|
+
* convoy run for hours. It is a distinct thing from `statement_timeout`: the
|
|
8
|
+
* latter caps how long a statement RUNS, the former caps how long it WAITS for
|
|
9
|
+
* a lock. Without it, contention on a hot row degrades into a strictly-ordered
|
|
10
|
+
* queue in which every waiter pins a backend for the sum of everyone ahead of
|
|
11
|
+
* it — 892 connections parked on locks with a 3.7-hour tail, on a database that
|
|
12
|
+
* was never short of capacity.
|
|
13
|
+
*
|
|
14
|
+
* Two subtleties this suite pins, both of which are easy to get wrong and
|
|
15
|
+
* silent when wrong:
|
|
16
|
+
*
|
|
17
|
+
* 1. The MIGRATION path must be exempt. App/Migrate.ts loads these same
|
|
18
|
+
* options and connects directly to the backend, where startup parameters
|
|
19
|
+
* really do apply. A 3s lock_timeout there would abort ACCESS EXCLUSIVE
|
|
20
|
+
* DDL against any table with live traffic. Only the two migrations that
|
|
21
|
+
* set their own `SET LOCAL lock_timeout` expect to fail that way.
|
|
22
|
+
*
|
|
23
|
+
* 2. The deadlines must be ORDERED so the server wins. The client-side
|
|
24
|
+
* `query_timeout` does not cancel anything — it abandons the query while
|
|
25
|
+
* the backend keeps running and keeps its place in the lock queue. That is
|
|
26
|
+
* how killed and scaled-down workers left orphaned statements holding the
|
|
27
|
+
* queue through pgbouncer. It used to be set equal to statement_timeout,
|
|
28
|
+
* and since the client timer starts before the packet reaches the backend,
|
|
29
|
+
* the client always won by a round trip and the server-side timeout never
|
|
30
|
+
* fired at all.
|
|
31
|
+
*
|
|
32
|
+
* The module reads env at import time, so each case re-imports it in isolation.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
interface DataSourceExtra {
|
|
36
|
+
lock_timeout?: number;
|
|
37
|
+
statement_timeout?: number;
|
|
38
|
+
query_timeout?: number;
|
|
39
|
+
idle_in_transaction_session_timeout?: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function loadExtra(env: Record<string, string | undefined>): DataSourceExtra {
|
|
43
|
+
let extra: DataSourceExtra = {};
|
|
44
|
+
|
|
45
|
+
jest.isolateModules(() => {
|
|
46
|
+
const previous: Record<string, string | undefined> = {};
|
|
47
|
+
|
|
48
|
+
for (const [key, value] of Object.entries(env)) {
|
|
49
|
+
previous[key] = process.env[key];
|
|
50
|
+
if (value === undefined) {
|
|
51
|
+
delete process.env[key];
|
|
52
|
+
} else {
|
|
53
|
+
process.env[key] = value;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
59
|
+
const options: {
|
|
60
|
+
default: { extra: DataSourceExtra };
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
62
|
+
} = require("../../../Server/Infrastructure/Postgres/DataSourceOptions");
|
|
63
|
+
/* eslint-enable @typescript-eslint/no-var-requires */
|
|
64
|
+
|
|
65
|
+
extra = options.default.extra;
|
|
66
|
+
} finally {
|
|
67
|
+
for (const [key, value] of Object.entries(previous)) {
|
|
68
|
+
if (value === undefined) {
|
|
69
|
+
delete process.env[key];
|
|
70
|
+
} else {
|
|
71
|
+
process.env[key] = value;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return extra;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
describe("Postgres connection deadlines", () => {
|
|
81
|
+
describe("lock_timeout", () => {
|
|
82
|
+
test("is applied on runtime pods", () => {
|
|
83
|
+
const extra: DataSourceExtra = loadExtra({
|
|
84
|
+
RUN_DATABASE_MIGRATIONS_ON_BOOT: "false",
|
|
85
|
+
DATABASE_LOCK_TIMEOUT_MS: undefined,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(extra.lock_timeout).toBe(3000);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("is configurable", () => {
|
|
92
|
+
const extra: DataSourceExtra = loadExtra({
|
|
93
|
+
RUN_DATABASE_MIGRATIONS_ON_BOOT: "false",
|
|
94
|
+
DATABASE_LOCK_TIMEOUT_MS: "1500",
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(extra.lock_timeout).toBe(1500);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/*
|
|
101
|
+
* The exemption is load-bearing, not a nicety. A migration that cannot
|
|
102
|
+
* wait for a lock cannot take one on a busy table at all.
|
|
103
|
+
*/
|
|
104
|
+
test("is NOT applied when this process runs migrations", () => {
|
|
105
|
+
const extra: DataSourceExtra = loadExtra({
|
|
106
|
+
RUN_DATABASE_MIGRATIONS_ON_BOOT: "true",
|
|
107
|
+
DATABASE_LOCK_TIMEOUT_MS: undefined,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
expect(extra.lock_timeout).toBeUndefined();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("can be disabled outright with 0", () => {
|
|
114
|
+
const extra: DataSourceExtra = loadExtra({
|
|
115
|
+
RUN_DATABASE_MIGRATIONS_ON_BOOT: "false",
|
|
116
|
+
DATABASE_LOCK_TIMEOUT_MS: "0",
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
expect(extra.lock_timeout).toBeUndefined();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe("deadline ordering", () => {
|
|
124
|
+
/*
|
|
125
|
+
* lock_timeout < statement_timeout, so a lock wait surfaces as
|
|
126
|
+
* `lock_not_available` rather than a generic statement timeout. The two
|
|
127
|
+
* want very different handling: one is contention worth retrying, the
|
|
128
|
+
* other is a query that needs fixing.
|
|
129
|
+
*/
|
|
130
|
+
test("a lock wait gives up well before the statement does", () => {
|
|
131
|
+
const extra: DataSourceExtra = loadExtra({
|
|
132
|
+
RUN_DATABASE_MIGRATIONS_ON_BOOT: "false",
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(extra.lock_timeout!).toBeLessThan(extra.statement_timeout!);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
/*
|
|
139
|
+
* statement_timeout < query_timeout, so the SERVER cancels first. If the
|
|
140
|
+
* client wins, the statement is only abandoned — the backend keeps
|
|
141
|
+
* running, keeps its lock, and keeps its place in the queue.
|
|
142
|
+
*/
|
|
143
|
+
test("the server cancels before the client gives up", () => {
|
|
144
|
+
const extra: DataSourceExtra = loadExtra({
|
|
145
|
+
RUN_DATABASE_MIGRATIONS_ON_BOOT: "false",
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
expect(extra.statement_timeout!).toBeLessThan(extra.query_timeout!);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("an explicitly configured query_timeout is still honoured", () => {
|
|
152
|
+
const extra: DataSourceExtra = loadExtra({
|
|
153
|
+
RUN_DATABASE_MIGRATIONS_ON_BOOT: "false",
|
|
154
|
+
DATABASE_QUERY_TIMEOUT_MS: "45000",
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
expect(extra.query_timeout).toBe(45000);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("the default query_timeout tracks a raised statement_timeout", () => {
|
|
161
|
+
const extra: DataSourceExtra = loadExtra({
|
|
162
|
+
RUN_DATABASE_MIGRATIONS_ON_BOOT: "false",
|
|
163
|
+
DATABASE_STATEMENT_TIMEOUT_MS: "60000",
|
|
164
|
+
DATABASE_QUERY_TIMEOUT_MS: undefined,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
expect(extra.statement_timeout).toBe(60000);
|
|
168
|
+
expect(extra.query_timeout!).toBeGreaterThan(60000);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe("existing deadlines are unchanged", () => {
|
|
173
|
+
test("idle-in-transaction is still bounded", () => {
|
|
174
|
+
const extra: DataSourceExtra = loadExtra({
|
|
175
|
+
RUN_DATABASE_MIGRATIONS_ON_BOOT: "false",
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
expect(extra.idle_in_transaction_session_timeout).toBe(60000);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
});
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import MasterAdminAuthorization from "../../../Server/Middleware/MasterAdminAuthorization";
|
|
2
|
+
import ProjectMiddleware from "../../../Server/Middleware/ProjectAuthorization";
|
|
3
|
+
import UserMiddleware from "../../../Server/Middleware/UserAuthorization";
|
|
4
|
+
import JSONWebToken from "../../../Server/Utils/JsonWebToken";
|
|
5
|
+
import Response from "../../../Server/Utils/Response";
|
|
6
|
+
import {
|
|
7
|
+
ExpressRequest,
|
|
8
|
+
ExpressResponse,
|
|
9
|
+
NextFunction,
|
|
10
|
+
} from "../../../Server/Utils/Express";
|
|
11
|
+
import NotAuthorizedException from "../../../Types/Exception/NotAuthorizedException";
|
|
12
|
+
import JSONWebTokenData from "../../../Types/JsonWebTokenData";
|
|
13
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
14
|
+
import { getJestSpyOn } from "../../Spy";
|
|
15
|
+
import { beforeEach, describe, expect, jest, test } from "@jest/globals";
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* isAuthorizedMasterAdminOrMasterApiKeyMiddleware is the SECOND production
|
|
19
|
+
* consumer of ProjectMiddleware.getApiKey (UserAuthorization is the first), and
|
|
20
|
+
* until now it had no test anywhere in the repo.
|
|
21
|
+
*
|
|
22
|
+
* That mattered when issue #3004 was fixed. getApiKey gained a `.trim()` and a
|
|
23
|
+
* UUID-shape guard, and this middleware inherited both without anyone looking
|
|
24
|
+
* at it:
|
|
25
|
+
*
|
|
26
|
+
* before: a padded header " <master-key> " became ObjectID(" <master-key> "),
|
|
27
|
+
* which isMasterApiKey's own UUID guard rejected, so the request fell
|
|
28
|
+
* through to the JWT check and was refused.
|
|
29
|
+
* after: getApiKey trims first, so the same header now authenticates.
|
|
30
|
+
*
|
|
31
|
+
* That is a widening of a master-admin path. It is a safe one — it admits only
|
|
32
|
+
* a caller who already holds the correct master key, and HTTP strips optional
|
|
33
|
+
* whitespace around field values anyway — but it is exactly the kind of change
|
|
34
|
+
* that should be pinned rather than left implicit. These tests pin both the
|
|
35
|
+
* widening and the boundary that did NOT move: a wrong key, a malformed key, or
|
|
36
|
+
* no key at all still gets nothing without a master-admin session.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
const MASTER_API_KEY: string = "8e1a3a52-6d64-4f1f-9a2e-5f0f9c1d2b34";
|
|
40
|
+
const OTHER_API_KEY: string = "1c9d7f40-2b83-4a55-8e70-6d4b9a0c3e12";
|
|
41
|
+
|
|
42
|
+
describe("MasterAdminAuthorization.isAuthorizedMasterAdminOrMasterApiKeyMiddleware", () => {
|
|
43
|
+
let request: ExpressRequest;
|
|
44
|
+
let response: ExpressResponse;
|
|
45
|
+
let next: NextFunction;
|
|
46
|
+
|
|
47
|
+
type RequestWithHeadersFunction = (
|
|
48
|
+
headers: Record<string, string | Array<string> | undefined>,
|
|
49
|
+
) => ExpressRequest;
|
|
50
|
+
|
|
51
|
+
const requestWithHeaders: RequestWithHeadersFunction = (
|
|
52
|
+
headers: Record<string, string | Array<string> | undefined>,
|
|
53
|
+
): ExpressRequest => {
|
|
54
|
+
return { headers: headers } as unknown as ExpressRequest;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
jest.restoreAllMocks();
|
|
59
|
+
jest.clearAllMocks();
|
|
60
|
+
|
|
61
|
+
response = {
|
|
62
|
+
status: jest.fn().mockReturnThis(),
|
|
63
|
+
json: jest.fn().mockReturnThis(),
|
|
64
|
+
send: jest.fn().mockReturnThis(),
|
|
65
|
+
} as unknown as ExpressResponse;
|
|
66
|
+
|
|
67
|
+
next = jest.fn() as unknown as NextFunction;
|
|
68
|
+
|
|
69
|
+
getJestSpyOn(Response, "sendErrorResponse").mockImplementation(() => {
|
|
70
|
+
return undefined as never;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
/*
|
|
74
|
+
* Stand in for the GlobalConfig lookup: only the one master key value is
|
|
75
|
+
* live. Spying here rather than on isMasterApiKey keeps the real UUID guard
|
|
76
|
+
* and the real "is it actually the master key" comparison in the test.
|
|
77
|
+
*/
|
|
78
|
+
getJestSpyOn(ProjectMiddleware, "isMasterApiKey").mockImplementation(((
|
|
79
|
+
apiKey: ObjectID,
|
|
80
|
+
): Promise<boolean> => {
|
|
81
|
+
return Promise.resolve(apiKey.toString() === MASTER_API_KEY);
|
|
82
|
+
}) as never);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe("when the master API key is presented", () => {
|
|
86
|
+
test("authorizes the request and never looks at the session", async () => {
|
|
87
|
+
const accessTokenSpy: jest.SpyInstance<any, any> = getJestSpyOn(
|
|
88
|
+
UserMiddleware,
|
|
89
|
+
"getAccessTokenFromExpressRequest",
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
request = requestWithHeaders({ apikey: MASTER_API_KEY });
|
|
93
|
+
|
|
94
|
+
await MasterAdminAuthorization.isAuthorizedMasterAdminOrMasterApiKeyMiddleware(
|
|
95
|
+
request,
|
|
96
|
+
response,
|
|
97
|
+
next,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
expect(next).toHaveBeenCalledTimes(1);
|
|
101
|
+
expect(next).toHaveBeenCalledWith();
|
|
102
|
+
expect(Response.sendErrorResponse).not.toHaveBeenCalled();
|
|
103
|
+
// The key short-circuits before the JWT branch is ever entered.
|
|
104
|
+
expect(accessTokenSpy).not.toHaveBeenCalled();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
/*
|
|
108
|
+
* The behaviour change introduced by the #3004 fix. Before getApiKey
|
|
109
|
+
* trimmed, this request fell through to the JWT check and was refused.
|
|
110
|
+
*/
|
|
111
|
+
test("accepts a whitespace-padded master key now that getApiKey trims", async () => {
|
|
112
|
+
request = requestWithHeaders({ apikey: ` ${MASTER_API_KEY}\t` });
|
|
113
|
+
|
|
114
|
+
await MasterAdminAuthorization.isAuthorizedMasterAdminOrMasterApiKeyMiddleware(
|
|
115
|
+
request,
|
|
116
|
+
response,
|
|
117
|
+
next,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
expect(next).toHaveBeenCalledTimes(1);
|
|
121
|
+
expect(Response.sendErrorResponse).not.toHaveBeenCalled();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
/*
|
|
125
|
+
* getApiKey normalizes whitespace but deliberately does NOT normalize case,
|
|
126
|
+
* so the value reaches the lookup exactly as the caller wrote it. Postgres
|
|
127
|
+
* compares `uuid` values by value rather than by the text they were written
|
|
128
|
+
* in, so a real instance still matches an upper-cased key — this asserts
|
|
129
|
+
* only the part that is ours: what we hand to the lookup.
|
|
130
|
+
*/
|
|
131
|
+
test("passes the key to the lookup verbatim, without case normalization", async () => {
|
|
132
|
+
request = requestWithHeaders({
|
|
133
|
+
apikey: ` ${MASTER_API_KEY.toUpperCase()} `,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
await MasterAdminAuthorization.isAuthorizedMasterAdminOrMasterApiKeyMiddleware(
|
|
137
|
+
request,
|
|
138
|
+
response,
|
|
139
|
+
next,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
expect(ProjectMiddleware.isMasterApiKey).toHaveBeenCalledTimes(1);
|
|
143
|
+
|
|
144
|
+
const lookedUpKey: ObjectID = (
|
|
145
|
+
ProjectMiddleware.isMasterApiKey as unknown as jest.Mock
|
|
146
|
+
).mock.calls[0]![0] as ObjectID;
|
|
147
|
+
|
|
148
|
+
expect(lookedUpKey.toString()).toBe(MASTER_API_KEY.toUpperCase());
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe("when the key cannot authorize the request", () => {
|
|
153
|
+
/*
|
|
154
|
+
* The boundary that did NOT move with the #3004 fix. Each of these must
|
|
155
|
+
* still be refused, because none of them is the master key.
|
|
156
|
+
*/
|
|
157
|
+
const unusableKeys: Array<[string, string]> = [
|
|
158
|
+
["a well-formed key that is not the master key", OTHER_API_KEY],
|
|
159
|
+
["an empty header", ""],
|
|
160
|
+
["a whitespace-only header", " "],
|
|
161
|
+
["a non-UUID string", "not-a-uuid"],
|
|
162
|
+
["a UUID with a segment missing", "8e1a3a52-6d64-4f1f-9a2e"],
|
|
163
|
+
[
|
|
164
|
+
"a UUID with a non-hex character",
|
|
165
|
+
"8e1a3a52-6d64-4f1f-9a2e-5f0f9c1d2bZZ",
|
|
166
|
+
],
|
|
167
|
+
["a SQL injection attempt", "' OR 1=1 --"],
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
test.each(unusableKeys)(
|
|
171
|
+
"refuses %s and falls through to the session check",
|
|
172
|
+
async (_label: string, apiKeyHeader: string) => {
|
|
173
|
+
request = requestWithHeaders({ apikey: apiKeyHeader });
|
|
174
|
+
|
|
175
|
+
await MasterAdminAuthorization.isAuthorizedMasterAdminOrMasterApiKeyMiddleware(
|
|
176
|
+
request,
|
|
177
|
+
response,
|
|
178
|
+
next,
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
expect(next).not.toHaveBeenCalled();
|
|
182
|
+
expect(Response.sendErrorResponse).toHaveBeenCalledTimes(1);
|
|
183
|
+
|
|
184
|
+
const error: NotAuthorizedException = (
|
|
185
|
+
Response.sendErrorResponse as unknown as jest.Mock
|
|
186
|
+
).mock.calls[0]![2] as NotAuthorizedException;
|
|
187
|
+
|
|
188
|
+
expect(error).toBeInstanceOf(NotAuthorizedException);
|
|
189
|
+
expect(error.message).toBe("Unauthorized: Access token is required.");
|
|
190
|
+
},
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
/*
|
|
194
|
+
* The UUID-shape guard added in the #3004 fix has to run BEFORE the key
|
|
195
|
+
* reaches the lookup: ApiKey.apiKey and GlobalConfig.masterApiKey are both
|
|
196
|
+
* Postgres uuid columns, and a non-UUID raises 22P02 as a raw
|
|
197
|
+
* QueryFailedError, which is not a OneUptime Exception and so escapes the
|
|
198
|
+
* error translator as a 500.
|
|
199
|
+
*/
|
|
200
|
+
test("never reaches the master key lookup with a malformed value", async () => {
|
|
201
|
+
request = requestWithHeaders({ apikey: "garbage" });
|
|
202
|
+
|
|
203
|
+
await MasterAdminAuthorization.isAuthorizedMasterAdminOrMasterApiKeyMiddleware(
|
|
204
|
+
request,
|
|
205
|
+
response,
|
|
206
|
+
next,
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
expect(ProjectMiddleware.isMasterApiKey).not.toHaveBeenCalled();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
/*
|
|
213
|
+
* Duplicate headers arrive from Node joined with a comma. Two keys is never
|
|
214
|
+
* one key, and it must not authenticate as whichever happened to be first.
|
|
215
|
+
*/
|
|
216
|
+
test("refuses duplicate apikey headers rather than using the first", async () => {
|
|
217
|
+
request = requestWithHeaders({
|
|
218
|
+
apikey: [MASTER_API_KEY, OTHER_API_KEY],
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
await MasterAdminAuthorization.isAuthorizedMasterAdminOrMasterApiKeyMiddleware(
|
|
222
|
+
request,
|
|
223
|
+
response,
|
|
224
|
+
next,
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
expect(ProjectMiddleware.isMasterApiKey).not.toHaveBeenCalled();
|
|
228
|
+
expect(next).not.toHaveBeenCalled();
|
|
229
|
+
expect(Response.sendErrorResponse).toHaveBeenCalledTimes(1);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test("refuses a request with no apikey header and no session", async () => {
|
|
233
|
+
request = requestWithHeaders({});
|
|
234
|
+
|
|
235
|
+
await MasterAdminAuthorization.isAuthorizedMasterAdminOrMasterApiKeyMiddleware(
|
|
236
|
+
request,
|
|
237
|
+
response,
|
|
238
|
+
next,
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
expect(ProjectMiddleware.isMasterApiKey).not.toHaveBeenCalled();
|
|
242
|
+
expect(next).not.toHaveBeenCalled();
|
|
243
|
+
expect(Response.sendErrorResponse).toHaveBeenCalledTimes(1);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
/*
|
|
247
|
+
* A lookup that blows up must not become an authorization. The catch in the
|
|
248
|
+
* middleware swallows it and falls through to the session check.
|
|
249
|
+
*/
|
|
250
|
+
test("falls through to the session check when the key lookup throws", async () => {
|
|
251
|
+
getJestSpyOn(ProjectMiddleware, "isMasterApiKey").mockImplementation(
|
|
252
|
+
(() => {
|
|
253
|
+
return Promise.reject(new Error("database is down"));
|
|
254
|
+
}) as never,
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
request = requestWithHeaders({ apikey: MASTER_API_KEY });
|
|
258
|
+
|
|
259
|
+
await MasterAdminAuthorization.isAuthorizedMasterAdminOrMasterApiKeyMiddleware(
|
|
260
|
+
request,
|
|
261
|
+
response,
|
|
262
|
+
next,
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
expect(next).not.toHaveBeenCalled();
|
|
266
|
+
expect(Response.sendErrorResponse).toHaveBeenCalledTimes(1);
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
describe("session fallback", () => {
|
|
271
|
+
test("authorizes a master admin session when no key is presented", async () => {
|
|
272
|
+
getJestSpyOn(
|
|
273
|
+
UserMiddleware,
|
|
274
|
+
"getAccessTokenFromExpressRequest",
|
|
275
|
+
).mockReturnValue("a.master.admin.token" as never);
|
|
276
|
+
|
|
277
|
+
getJestSpyOn(JSONWebToken, "decode").mockReturnValue({
|
|
278
|
+
isMasterAdmin: true,
|
|
279
|
+
} as unknown as JSONWebTokenData as never);
|
|
280
|
+
|
|
281
|
+
request = requestWithHeaders({});
|
|
282
|
+
|
|
283
|
+
await MasterAdminAuthorization.isAuthorizedMasterAdminOrMasterApiKeyMiddleware(
|
|
284
|
+
request,
|
|
285
|
+
response,
|
|
286
|
+
next,
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
expect(next).toHaveBeenCalledTimes(1);
|
|
290
|
+
expect(Response.sendErrorResponse).not.toHaveBeenCalled();
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
test("refuses a session that is not a master admin", async () => {
|
|
294
|
+
getJestSpyOn(
|
|
295
|
+
UserMiddleware,
|
|
296
|
+
"getAccessTokenFromExpressRequest",
|
|
297
|
+
).mockReturnValue("an.ordinary.user.token" as never);
|
|
298
|
+
|
|
299
|
+
getJestSpyOn(JSONWebToken, "decode").mockReturnValue({
|
|
300
|
+
isMasterAdmin: false,
|
|
301
|
+
} as unknown as JSONWebTokenData as never);
|
|
302
|
+
|
|
303
|
+
request = requestWithHeaders({});
|
|
304
|
+
|
|
305
|
+
await MasterAdminAuthorization.isAuthorizedMasterAdminOrMasterApiKeyMiddleware(
|
|
306
|
+
request,
|
|
307
|
+
response,
|
|
308
|
+
next,
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
expect(next).not.toHaveBeenCalled();
|
|
312
|
+
|
|
313
|
+
const error: NotAuthorizedException = (
|
|
314
|
+
Response.sendErrorResponse as unknown as jest.Mock
|
|
315
|
+
).mock.calls[0]![2] as NotAuthorizedException;
|
|
316
|
+
|
|
317
|
+
expect(error.message).toBe(
|
|
318
|
+
"Unauthorized: Only master admins can perform this action.",
|
|
319
|
+
);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
/*
|
|
323
|
+
* An unusable apikey header must not cost a caller their valid session on
|
|
324
|
+
* these routes. This middleware is the one place where the presence-based
|
|
325
|
+
* routing in UserAuthorization does NOT apply: it falls through rather than
|
|
326
|
+
* failing fast.
|
|
327
|
+
*/
|
|
328
|
+
test("still honours a master admin session when an unusable key is also sent", async () => {
|
|
329
|
+
getJestSpyOn(
|
|
330
|
+
UserMiddleware,
|
|
331
|
+
"getAccessTokenFromExpressRequest",
|
|
332
|
+
).mockReturnValue("a.master.admin.token" as never);
|
|
333
|
+
|
|
334
|
+
getJestSpyOn(JSONWebToken, "decode").mockReturnValue({
|
|
335
|
+
isMasterAdmin: true,
|
|
336
|
+
} as unknown as JSONWebTokenData as never);
|
|
337
|
+
|
|
338
|
+
request = requestWithHeaders({ apikey: "" });
|
|
339
|
+
|
|
340
|
+
await MasterAdminAuthorization.isAuthorizedMasterAdminOrMasterApiKeyMiddleware(
|
|
341
|
+
request,
|
|
342
|
+
response,
|
|
343
|
+
next,
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
expect(next).toHaveBeenCalledTimes(1);
|
|
347
|
+
expect(Response.sendErrorResponse).not.toHaveBeenCalled();
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
});
|