@oneuptime/common 12.0.33 → 12.0.34
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/RumSession.ts +117 -1
- package/Models/AnalyticsModels/RumSessionChunk.ts +13 -0
- package/Models/DatabaseModels/AlertCustomField.ts +77 -3
- package/Models/DatabaseModels/ApiKeyPermission.ts +3 -27
- package/Models/DatabaseModels/IncidentCustomField.ts +77 -3
- package/Models/DatabaseModels/InventoryItemCustomField.ts +77 -3
- package/Models/DatabaseModels/MonitorCustomField.ts +77 -3
- package/Models/DatabaseModels/OnCallDutyPolicyCustomField.ts +77 -3
- package/Models/DatabaseModels/RumApplication.ts +6 -6
- package/Models/DatabaseModels/ScheduledMaintenanceCustomField.ts +77 -3
- package/Models/DatabaseModels/StatusPageCustomField.ts +77 -3
- package/Models/DatabaseModels/TeamCustomField.ts +77 -3
- package/Models/DatabaseModels/TeamMember.ts +0 -9
- package/Models/DatabaseModels/TeamMemberCustomField.ts +77 -3
- package/Models/DatabaseModels/TeamPermission.ts +3 -24
- package/Models/DatabaseModels/TelemetryIngestionKey.ts +260 -0
- package/Models/DatabaseModels/UserTelegram.ts +0 -4
- package/Scripts/benchmark-fanin-capacity.js +181 -0
- package/Server/API/TelemetryAPI.ts +1284 -164
- package/Server/API/UserNotificationSettingAPI.ts +55 -0
- package/Server/API/UserTelegramAPI.ts +48 -4
- package/Server/EnvironmentConfig.ts +35 -2
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.ts +91 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.ts +67 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.ts +139 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.ts +121 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Infrastructure/QueueWorker.ts +20 -14
- package/Server/Infrastructure/Semaphore.ts +2 -0
- package/Server/Middleware/TelemetryIngest.ts +453 -7
- package/Server/Services/AccessTokenService.ts +1 -0
- package/Server/Services/AlertCustomFieldService.ts +98 -0
- package/Server/Services/AlertService.ts +37 -0
- package/Server/Services/ApiKeyPermissionService.ts +461 -29
- package/Server/Services/CustomFieldMappingService.ts +879 -0
- package/Server/Services/GlobalConfigService.ts +194 -0
- package/Server/Services/IncidentCustomFieldService.ts +98 -0
- package/Server/Services/IncidentService.ts +35 -0
- package/Server/Services/MetricService.ts +194 -0
- package/Server/Services/MonitorService.ts +32 -0
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +78 -25
- package/Server/Services/ProjectService.ts +22 -0
- package/Server/Services/RoutineEmailSettingsService.ts +73 -0
- package/Server/Services/RumSessionReplayViewService.ts +104 -24
- package/Server/Services/ScheduledMaintenanceCustomFieldService.ts +98 -0
- package/Server/Services/ScheduledMaintenanceService.ts +32 -0
- package/Server/Services/TeamMemberService.ts +78 -0
- package/Server/Services/TeamPermissionService.ts +235 -3
- package/Server/Services/TelemetryIngestionKeyService.ts +722 -19
- package/Server/Services/UserNotificationSettingService.ts +34 -6
- package/Server/Services/UserTelegramService.ts +326 -5
- package/Server/Types/Database/QueryHelper.ts +2 -0
- package/Server/Utils/APIKey/AccessPermission.ts +5 -2
- package/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.ts +54 -0
- package/Server/Utils/CustomField/CustomFieldMappingRegistry.ts +415 -0
- package/Server/Utils/CustomField/CustomFieldMappingValidator.ts +335 -0
- package/Server/Utils/DataSource/EgressGuard.ts +177 -8
- package/Server/Utils/EmailRollup/EmailRollupConstants.ts +38 -5
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +57 -4
- package/Server/Utils/FrontendEnvironment.ts +40 -0
- package/Server/Utils/LogRedaction.ts +20 -0
- package/Server/Utils/Logger.ts +11 -0
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +338 -77
- package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +30 -4
- package/Server/Utils/Monitor/MonitorAlert.ts +29 -6
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +110 -15
- package/Server/Utils/Monitor/MonitorIncident.ts +22 -6
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +29 -0
- package/Server/Utils/Monitor/SeriesContextEnricher.ts +304 -0
- package/Server/Utils/SSRFProtection.ts +217 -10
- package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +239 -138
- package/Server/Utils/SessionReplay/SessionReplayHealthCounters.ts +305 -0
- package/Server/Utils/SessionReplay/SessionReplayReadService.ts +1430 -289
- package/Server/Utils/StartServer.ts +2 -17
- package/Server/Utils/TelegramVerificationToken.ts +185 -0
- package/Server/Utils/Telemetry/PinServiceName.ts +197 -0
- package/Server/Utils/Telemetry/TelemetryFanInWriter.ts +38 -16
- package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +92 -0
- package/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.ts +217 -0
- package/Server/Utils/VM/VMAPI.ts +1 -0
- package/Server/Utils/VM/VMRunner.ts +975 -95
- package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +202 -0
- package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +404 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +468 -0
- package/Tests/App/Dashboard/NotificationEmailPreferences.test.tsx +399 -0
- package/Tests/App/StatusPage/StatusPageLastUpdated.test.tsx +263 -0
- package/Tests/App/StatusPage/StatusPageOverviewLiveAndSearch.test.tsx +753 -0
- package/Tests/App/StatusPage/StatusPageResourceSearchBox.test.tsx +224 -0
- package/Tests/Models/AnalyticsModels/RumSessionReplayColumns.test.ts +262 -0
- package/Tests/Models/CustomFieldMappingColumns.test.ts +166 -0
- package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +20 -6
- package/Tests/ResponsiveVisibility.test.ts +115 -0
- package/Tests/ResponsiveVisibility.ts +183 -0
- package/Tests/Server/API/SessionReplayAPI.test.ts +1940 -216
- package/Tests/Server/API/UserNotificationSettingAPI.test.ts +186 -0
- package/Tests/Server/API/UserTelegramAPISecurity.test.ts +231 -0
- package/Tests/Server/EnvironmentConfigFrontendSecurity.test.ts +234 -0
- package/Tests/Server/Infrastructure/Postgres/CustomFieldValueMappingMigration.test.ts +202 -0
- package/Tests/Server/Infrastructure/Postgres/InventoryItemArchiveMigration.test.ts +41 -0
- package/Tests/Server/Infrastructure/Postgres/SessionReplayRecordEverySessionByDefaultMigration.test.ts +169 -0
- package/Tests/Server/Infrastructure/QueueWorkerTimeout.test.ts +210 -0
- package/Tests/Server/Infrastructure/TelemetryExporterDeploymentConfig.test.ts +130 -0
- package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +4 -1
- package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +1163 -0
- package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +5 -3
- package/Tests/Server/Services/AddTelemetryIngestionKeyTypeMigration.test.ts +555 -0
- package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +678 -0
- package/Tests/Server/Services/ApiKeyPermissionService.test.ts +276 -28
- package/Tests/Server/Services/CustomFieldDropdownOptionsColumnWidth.test.ts +431 -0
- package/Tests/Server/Services/CustomFieldMappingService.test.ts +850 -0
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +32 -0
- package/Tests/Server/Services/GlobalConfigService.test.ts +414 -1
- package/Tests/Server/Services/MetricRawEntityKeyPrune.test.ts +592 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +226 -1
- package/Tests/Server/Services/RoutineEmailSettingsPostgres.test.ts +329 -0
- package/Tests/Server/Services/RumSessionReplayViewService.test.ts +267 -0
- package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +9 -0
- package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +9 -0
- package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +834 -0
- package/Tests/Server/Services/TelemetryIngestionKeyPolicyResolution.test.ts +814 -0
- package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +998 -0
- package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +141 -0
- package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +18 -10
- package/Tests/Server/Services/UserTelegramVerificationSecurity.test.ts +688 -0
- package/Tests/Server/Utils/AI/SRE/Insights/FixRouting.test.ts +497 -0
- package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +383 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +7 -3
- package/Tests/Server/Utils/AnalyticsDatabase/ClusterConfig.test.ts +315 -0
- package/Tests/Server/Utils/CustomField/CustomFieldMappingValidator.test.ts +437 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +300 -11
- package/Tests/Server/Utils/EmailRollup/EmailRollupBurstWindow.test.ts +83 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1 -1
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerPreferences.test.ts +362 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +77 -1
- package/Tests/Server/Utils/FrontendEnvironment.test.ts +190 -0
- package/Tests/Server/Utils/LogRedaction.test.ts +26 -0
- package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +23 -9
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +584 -0
- package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestHeaderCriteria.test.ts +236 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +437 -0
- package/Tests/Server/Utils/Monitor/MonitorTemplateUtilSeriesContext.test.ts +176 -0
- package/Tests/Server/Utils/Monitor/SeriesContextEnricher.test.ts +356 -0
- package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +595 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +198 -1
- package/Tests/Server/Utils/SessionReplay/SessionReplayHealthCounters.test.ts +453 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1378 -0
- package/Tests/Server/Utils/SessionReplayOriginAllowListRefactor.test.ts +420 -0
- package/Tests/Server/Utils/TelegramVerificationToken.test.ts +253 -0
- package/Tests/Server/Utils/Telemetry/PinServiceName.test.ts +666 -0
- package/Tests/Server/Utils/Telemetry/TelemetryFanInWriterCapacity.test.ts +458 -0
- package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +424 -0
- package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.test.ts +528 -0
- package/Tests/Server/Utils/TelemetryExporterEnvironment.test.ts +56 -0
- package/Tests/Server/Utils/VM/VMRunnerHostBridgeLatency.test.ts +74 -0
- package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +100 -7
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +1176 -6
- package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +220 -0
- package/Tests/Types/CustomField/CustomFieldValueMapping.test.ts +348 -0
- package/Tests/Types/JSONFunctions.test.ts +260 -0
- package/Tests/Types/Monitor/CephAlertTemplates.test.ts +422 -53
- package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +495 -15
- package/Tests/Types/Monitor/DockerSwarmAlertTemplates.test.ts +191 -45
- package/Tests/Types/Monitor/HostAlertTemplates.test.ts +370 -42
- package/Tests/Types/Monitor/IotAlertTemplates.test.ts +375 -20
- package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +636 -42
- package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +189 -0
- package/Tests/Types/Monitor/KubernetesTemplateGroupByKeys.test.ts +95 -14
- package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +190 -21
- package/Tests/Types/Monitor/ProxmoxAlertTemplates.test.ts +352 -22
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationAlertDebuggability.test.ts +363 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +93 -18
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +259 -0
- package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +476 -0
- package/Tests/Types/Monitor/RumAlertTemplates.test.ts +136 -0
- package/Tests/Types/Monitor/SeriesContext/SeriesDebugHints.test.ts +661 -0
- package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +507 -0
- package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +270 -0
- package/Tests/Types/Monitor/TemplateGroupByKeys.test.ts +38 -10
- package/Tests/Types/Monitor/Utils/RecommendationCriteriaAssertions.ts +102 -0
- package/Tests/Types/NotificationSetting/RoutineEmailEvents.test.ts +47 -0
- package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +608 -0
- package/Tests/Types/Rum/SessionReplayCustomEvents.test.ts +434 -0
- package/Tests/Types/WebsiteRequest.test.ts +285 -3
- package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +16 -3
- package/Tests/UI/Components/Charts/ChartTrailingBucketGap.test.ts +691 -0
- package/Tests/UI/Components/ComponentsModal.test.tsx +12 -4
- package/Tests/UI/Components/ComponentsModalUsability.test.tsx +518 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetailMapping.test.tsx +324 -0
- package/Tests/UI/Components/CustomFields/MapFromCustomFieldInput.test.tsx +176 -0
- package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +484 -0
- package/Tests/UI/Components/HeaderRightRail.test.tsx +157 -0
- package/Tests/UI/Components/IconDropdownItem.test.tsx +102 -0
- package/Tests/UI/Components/JSONTablePrototypePollution.test.tsx +117 -0
- package/Tests/UI/Components/KeyboardShortcutsModal.test.tsx +214 -0
- package/Tests/UI/Components/ModelTable/ModelTableWrapContent.test.tsx +561 -0
- package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +302 -0
- package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +28 -12
- package/Tests/UI/Components/ShortcutDialogGuard.test.tsx +74 -0
- package/Tests/UI/Components/StatusPage/ResourceGroupSectionAutoExpand.test.tsx +248 -0
- package/Tests/UI/Components/TableCellWrapping.test.tsx +625 -0
- package/Tests/UI/Components/TableLoadingStates.test.tsx +205 -0
- package/Tests/UI/Components/Workflow/NodePlacement.test.ts +148 -0
- package/Tests/UI/Components/Workflow/Workflow.test.tsx +981 -0
- package/Tests/UI/ConfigBrowserTelemetry.test.ts +70 -0
- package/Tests/UI/Rum/ChunkLoader.test.ts +1036 -2
- package/Tests/UI/Rum/FidelityNotices.test.ts +187 -0
- package/Tests/UI/Rum/InactivityMap.test.ts +341 -0
- package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +259 -0
- package/Tests/UI/Rum/RecordingHealthCard.test.tsx +855 -0
- package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +594 -0
- package/Tests/UI/Rum/ReplayCard.test.tsx +451 -0
- package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +536 -0
- package/Tests/UI/Rum/ReplayEngine.test.ts +2503 -0
- package/Tests/UI/Rum/ReplayEngineTypes.test.ts +171 -0
- package/Tests/UI/Rum/ReplayHeader.test.tsx +711 -0
- package/Tests/UI/Rum/ReplayLink.test.tsx +119 -0
- package/Tests/UI/Rum/ReplayPinControl.test.tsx +408 -0
- package/Tests/UI/Rum/ReplayPlaybackIntent.test.ts +152 -0
- package/Tests/UI/Rum/ReplayRail.test.tsx +1296 -0
- package/Tests/UI/Rum/ReplayRailDetail.test.tsx +900 -0
- package/Tests/UI/Rum/ReplayScrubber.test.tsx +763 -147
- package/Tests/UI/Rum/ReplaySignalTypes.test.ts +189 -0
- package/Tests/UI/Rum/ReplaySignals.test.ts +1579 -0
- package/Tests/UI/Rum/ReplayStage.test.tsx +396 -473
- package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +918 -0
- package/Tests/UI/Rum/ReplayTimeline.test.tsx +696 -0
- package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +499 -0
- package/Tests/UI/Rum/SessionReplaySearchBar.test.tsx +346 -0
- package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +545 -0
- package/Tests/UI/Rum/SessionReplayTable.test.tsx +991 -0
- package/Tests/UI/Rum/TargetedCapturePanel.test.tsx +254 -0
- package/Tests/UI/Telemetry/BrowserExporterIsolation.test.ts +71 -0
- package/Tests/UI/Utils/GlobalKeyboardShortcut.test.ts +344 -0
- package/Tests/Utils/API.test.ts +308 -0
- package/Tests/Utils/HTTPResponseBodyReader.test.ts +323 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveryScanStatus.test.ts +117 -0
- package/Tests/Utils/Rum/ChunkMath.test.ts +83 -0
- package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +993 -0
- package/Tests/Utils/Rum/SessionReplayStringMap.test.ts +245 -0
- package/Tests/Utils/StatusPage/ResourceSearch.test.ts +631 -0
- package/Tests/Utils/Telemetry/OriginAllowList.test.ts +633 -0
- package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +461 -0
- package/Tests/Utils/ValueFormatter.test.ts +148 -0
- package/Types/CustomField/CustomFieldMappingCatalog.ts +161 -0
- package/Types/CustomField/CustomFieldMappingSourceResource.ts +19 -0
- package/Types/CustomField/CustomFieldValueMapping.ts +288 -0
- package/Types/Icon/IconProp.ts +1 -0
- package/Types/JSONFunctions.ts +189 -43
- package/Types/Monitor/CephAlertTemplates.ts +157 -195
- package/Types/Monitor/DockerAlertTemplates.ts +338 -128
- package/Types/Monitor/DockerSwarmAlertTemplates.ts +95 -112
- package/Types/Monitor/HostAlertTemplates.ts +302 -130
- package/Types/Monitor/IotAlertTemplates.ts +112 -104
- package/Types/Monitor/KubernetesAlertTemplates.ts +415 -224
- package/Types/Monitor/KubernetesMetricCatalog.ts +23 -19
- package/Types/Monitor/PodmanAlertTemplates.ts +116 -163
- package/Types/Monitor/ProxmoxAlertTemplates.ts +217 -99
- package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +98 -6
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +44 -7
- package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +383 -0
- package/Types/Monitor/RumAlertTemplates.ts +46 -7
- package/Types/Monitor/SeriesContext/SeriesDebugHints.ts +596 -0
- package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +554 -0
- package/Types/Monitor/ServiceAlertTemplates.ts +98 -11
- package/Types/Monitor/UptimeHistoryLabels.ts +56 -0
- package/Types/NotificationSetting/RoutineEmailEvents.ts +30 -0
- package/Types/Rum/SessionReplay.ts +209 -0
- package/Types/Rum/SessionReplayApi.ts +722 -0
- package/Types/Rum/SessionReplayCaptureTrigger.ts +21 -12
- package/Types/Rum/SessionReplayConsentMode.ts +11 -7
- package/Types/Rum/SessionReplayCustomEvents.ts +549 -0
- package/Types/Rum/SessionReplayHealth.ts +238 -0
- package/Types/Telemetry/TelemetryIngestSurface.ts +95 -0
- package/Types/Telemetry/TelemetryIngestionKeyPolicy.ts +75 -0
- package/Types/Telemetry/TelemetryIngestionKeyType.ts +29 -0
- package/Types/WebsiteRequest.ts +85 -3
- package/UI/Components/Charts/Area/AreaChart.tsx +13 -2
- package/UI/Components/Charts/Bar/BarChart.tsx +6 -2
- package/UI/Components/Charts/Line/LineChart.tsx +13 -2
- package/UI/Components/Charts/Types/XAxis/XAxis.ts +29 -0
- package/UI/Components/Charts/Utils/DataPoint.ts +22 -3
- package/UI/Components/Charts/Utils/TimeAnnotation.ts +76 -9
- package/UI/Components/Charts/Utils/XAxis.ts +217 -0
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +143 -25
- package/UI/Components/CustomFields/MapFromCustomFieldInput.tsx +216 -0
- package/UI/Components/Graphs/DayUptimeGraph.tsx +173 -8
- package/UI/Components/Graphs/UptimeBarTooltip.tsx +22 -278
- package/UI/Components/Graphs/UptimeDaySummary.tsx +327 -0
- package/UI/Components/Header/Header.tsx +25 -9
- package/UI/Components/Header/IconDropdown/IconDropdownItem.tsx +10 -1
- package/UI/Components/Header/IconDropdown/IconDropdownMenu.tsx +6 -1
- package/UI/Components/Header/ProjectPicker/ProjectPicker.tsx +6 -1
- package/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.tsx +6 -1
- package/UI/Components/Icon/Icon.tsx +11 -0
- package/UI/Components/JSONTable/JSONTable.tsx +2 -2
- package/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.tsx +125 -0
- package/UI/Components/KeyboardShortcut/Screenshots/README.md +19 -0
- package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-command-palette.png +0 -0
- package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog-dark.png +0 -0
- package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog.png +0 -0
- package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-help-menu.png +0 -0
- package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-narrow.png +0 -0
- package/UI/Components/ModelTable/Column.ts +15 -0
- package/UI/Components/Monitor/SeriesDebugCommandsViewer.tsx +64 -0
- package/UI/Components/Monitor/SeriesLabelsViewer.tsx +93 -0
- package/UI/Components/MonitorGraphs/Uptime.tsx +14 -2
- package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +63 -10
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +44 -0
- package/UI/Components/StatusPage/ResourceGroupSection.tsx +40 -0
- package/UI/Components/Table/CellClassName.ts +81 -0
- package/UI/Components/Table/TableRow.tsx +20 -14
- package/UI/Components/Table/TableSkeletonRows.tsx +9 -9
- package/UI/Components/Table/Types/Column.ts +36 -0
- package/UI/Components/Tooltip/Tooltip.tsx +11 -1
- package/UI/Components/Workflow/ComponentsModal.tsx +60 -39
- package/UI/Components/Workflow/NodePlacement.ts +57 -0
- package/UI/Components/Workflow/Workflow.tsx +47 -18
- package/UI/Config.ts +15 -33
- package/UI/Utils/GlobalKeyboardShortcut.ts +208 -0
- package/UI/Utils/Telemetry/BrowserTelemetryConfig.ts +28 -0
- package/UI/Utils/Telemetry/Telemetry.ts +10 -8
- package/Utils/API.ts +129 -3
- package/Utils/HTTPResponseBodyReader.ts +221 -0
- package/Utils/NetworkDiscovery/DiscoveryScanStatus.ts +77 -0
- package/Utils/Rum/ChunkMath.ts +106 -0
- package/Utils/Rum/SessionReplayHealth.ts +732 -0
- package/Utils/Rum/SessionReplayStringMap.ts +226 -0
- package/Utils/Schema/ModelSchema.ts +1 -0
- package/Utils/StatusPage/ResourceSearch.ts +290 -0
- package/Utils/Telemetry/OriginAllowList.ts +355 -0
- package/Utils/Uptime/DayUptimeGraphUtil.ts +205 -0
- package/Utils/ValueFormatter.ts +35 -1
- package/build/dist/Models/AnalyticsModels/RumSession.js +102 -19
- package/build/dist/Models/AnalyticsModels/RumSession.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/RumSessionChunk.js +11 -9
- package/build/dist/Models/AnalyticsModels/RumSessionChunk.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/AlertCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ApiKeyPermission.js +3 -27
- package/build/dist/Models/DatabaseModels/ApiKeyPermission.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/MonitorCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js +6 -6
- package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/StatusPageCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/TeamCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamMember.js +0 -9
- package/build/dist/Models/DatabaseModels/TeamMember.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js +79 -3
- package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamPermission.js +3 -24
- package/build/dist/Models/DatabaseModels/TeamPermission.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +267 -0
- package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserTelegram.js +0 -4
- package/build/dist/Models/DatabaseModels/UserTelegram.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +769 -109
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/API/UserNotificationSettingAPI.js +35 -0
- package/build/dist/Server/API/UserNotificationSettingAPI.js.map +1 -0
- package/build/dist/Server/API/UserTelegramAPI.js +28 -6
- package/build/dist/Server/API/UserTelegramAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +29 -2
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js +60 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js +53 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js +82 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js +46 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +19 -7
- package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
- package/build/dist/Server/Infrastructure/Semaphore.js +1 -0
- package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +315 -8
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AccessTokenService.js +1 -0
- package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
- package/build/dist/Server/Services/AlertCustomFieldService.js +93 -0
- package/build/dist/Server/Services/AlertCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +34 -0
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js +331 -28
- package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
- package/build/dist/Server/Services/CustomFieldMappingService.js +614 -0
- package/build/dist/Server/Services/CustomFieldMappingService.js.map +1 -0
- package/build/dist/Server/Services/GlobalConfigService.js +133 -0
- package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
- package/build/dist/Server/Services/IncidentCustomFieldService.js +93 -0
- package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +32 -0
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/MetricService.js +163 -0
- package/build/dist/Server/Services/MetricService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +29 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +79 -27
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +22 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RoutineEmailSettingsService.js +69 -0
- package/build/dist/Server/Services/RoutineEmailSettingsService.js.map +1 -0
- package/build/dist/Server/Services/RumSessionReplayViewService.js +86 -24
- package/build/dist/Server/Services/RumSessionReplayViewService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js +93 -0
- package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +29 -0
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +62 -2
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamPermissionService.js +166 -3
- package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js +562 -18
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js +26 -6
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserTelegramService.js +257 -4
- package/build/dist/Server/Services/UserTelegramService.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/APIKey/AccessPermission.js +2 -2
- package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
- package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js +27 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js.map +1 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js +226 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js.map +1 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js +189 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +121 -7
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +38 -5
- package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +44 -2
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
- package/build/dist/Server/Utils/FrontendEnvironment.js +33 -0
- package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -0
- package/build/dist/Server/Utils/LogRedaction.js +20 -0
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
- package/build/dist/Server/Utils/Logger.js +10 -0
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +287 -68
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +20 -4
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +29 -6
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +88 -13
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +22 -6
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +22 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js +237 -0
- package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js.map +1 -0
- package/build/dist/Server/Utils/SSRFProtection.js +136 -9
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +174 -89
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js +223 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +945 -164
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +3 -14
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/TelegramVerificationToken.js +129 -0
- package/build/dist/Server/Utils/TelegramVerificationToken.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/PinServiceName.js +163 -0
- package/build/dist/Server/Utils/Telemetry/PinServiceName.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js +28 -15
- package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +64 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js +171 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js.map +1 -0
- package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMRunner.js +780 -69
- package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +60 -0
- package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js +20 -0
- package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldValueMapping.js +141 -0
- package/build/dist/Types/CustomField/CustomFieldValueMapping.js.map +1 -0
- package/build/dist/Types/Icon/IconProp.js +1 -0
- package/build/dist/Types/Icon/IconProp.js.map +1 -1
- package/build/dist/Types/JSONFunctions.js +118 -37
- package/build/dist/Types/JSONFunctions.js.map +1 -1
- package/build/dist/Types/Monitor/CephAlertTemplates.js +130 -171
- package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/DockerAlertTemplates.js +286 -121
- package/build/dist/Types/Monitor/DockerAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js +84 -105
- package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/HostAlertTemplates.js +250 -122
- package/build/dist/Types/Monitor/HostAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/IotAlertTemplates.js +81 -81
- package/build/dist/Types/Monitor/IotAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +375 -215
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +19 -19
- package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/PodmanAlertTemplates.js +104 -153
- package/build/dist/Types/Monitor/PodmanAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +156 -91
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +67 -6
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +38 -7
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +261 -0
- package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -0
- package/build/dist/Types/Monitor/RumAlertTemplates.js +46 -7
- package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js +422 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js.map +1 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +441 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -0
- package/build/dist/Types/Monitor/ServiceAlertTemplates.js +79 -15
- package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/UptimeHistoryLabels.js +17 -0
- package/build/dist/Types/Monitor/UptimeHistoryLabels.js.map +1 -0
- package/build/dist/Types/NotificationSetting/RoutineEmailEvents.js +29 -0
- package/build/dist/Types/NotificationSetting/RoutineEmailEvents.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplay.js +117 -0
- package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayApi.js +181 -0
- package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js +21 -12
- package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayConsentMode.js +11 -7
- package/build/dist/Types/Rum/SessionReplayConsentMode.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayCustomEvents.js +172 -0
- package/build/dist/Types/Rum/SessionReplayCustomEvents.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplayHealth.js +37 -0
- package/build/dist/Types/Rum/SessionReplayHealth.js.map +1 -0
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +85 -0
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -0
- package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js +15 -0
- package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js.map +1 -0
- package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js +30 -0
- package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js.map +1 -0
- package/build/dist/Types/WebsiteRequest.js +55 -3
- package/build/dist/Types/WebsiteRequest.js.map +1 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +13 -2
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +6 -2
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js +13 -2
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Types/XAxis/XAxis.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js +15 -3
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +40 -9
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/XAxis.js +186 -0
- package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +80 -6
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js +118 -0
- package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js.map +1 -0
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +112 -7
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
- package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -162
- package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
- package/build/dist/UI/Components/Graphs/UptimeDaySummary.js +181 -0
- package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -0
- package/build/dist/UI/Components/Header/Header.js +2 -3
- package/build/dist/UI/Components/Header/Header.js.map +1 -1
- package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js +2 -1
- package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js.map +1 -1
- package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js +7 -1
- package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js.map +1 -1
- package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js +7 -1
- package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js.map +1 -1
- package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js +7 -1
- package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +5 -0
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/JSONTable/JSONTable.js +2 -2
- package/build/dist/UI/Components/JSONTable/JSONTable.js.map +1 -1
- package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js +35 -0
- package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js.map +1 -0
- package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js +34 -0
- package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js.map +1 -0
- package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js +49 -0
- package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js.map +1 -0
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js +1 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +32 -6
- package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +38 -0
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +22 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -1
- package/build/dist/UI/Components/Table/CellClassName.js +55 -0
- package/build/dist/UI/Components/Table/CellClassName.js.map +1 -0
- package/build/dist/UI/Components/Table/TableRow.js +16 -13
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/UI/Components/Table/TableSkeletonRows.js +9 -8
- package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js +25 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentsModal.js +47 -30
- package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/NodePlacement.js +37 -0
- package/build/dist/UI/Components/Workflow/NodePlacement.js.map +1 -0
- package/build/dist/UI/Components/Workflow/Workflow.js +35 -18
- package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
- package/build/dist/UI/Config.js +10 -20
- package/build/dist/UI/Config.js.map +1 -1
- package/build/dist/UI/Utils/GlobalKeyboardShortcut.js +138 -0
- package/build/dist/UI/Utils/GlobalKeyboardShortcut.js.map +1 -0
- package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js +14 -0
- package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js.map +1 -0
- package/build/dist/UI/Utils/Telemetry/Telemetry.js +7 -5
- package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Utils/API.js +67 -5
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/HTTPResponseBodyReader.js +157 -0
- package/build/dist/Utils/HTTPResponseBodyReader.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js +69 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js.map +1 -0
- package/build/dist/Utils/Rum/ChunkMath.js +76 -0
- package/build/dist/Utils/Rum/ChunkMath.js.map +1 -1
- package/build/dist/Utils/Rum/SessionReplayHealth.js +534 -0
- package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -0
- package/build/dist/Utils/Rum/SessionReplayStringMap.js +165 -0
- package/build/dist/Utils/Rum/SessionReplayStringMap.js.map +1 -0
- package/build/dist/Utils/Schema/ModelSchema.js +1 -0
- package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
- package/build/dist/Utils/StatusPage/ResourceSearch.js +200 -0
- package/build/dist/Utils/StatusPage/ResourceSearch.js.map +1 -0
- package/build/dist/Utils/Telemetry/OriginAllowList.js +299 -0
- package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -0
- package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +147 -0
- package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -0
- package/build/dist/Utils/ValueFormatter.js +32 -1
- package/build/dist/Utils/ValueFormatter.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
import {
|
|
2
|
+
afterEach,
|
|
3
|
+
beforeEach,
|
|
4
|
+
describe,
|
|
5
|
+
expect,
|
|
6
|
+
jest,
|
|
7
|
+
test,
|
|
8
|
+
} from "@jest/globals";
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* The per-key ceiling that makes a Browser ingestion key safe to publish.
|
|
12
|
+
*
|
|
13
|
+
* A browser key lives in the page: anyone who views source has it. The origin
|
|
14
|
+
* allowlist bounds WHO can replay a scraped key, but nothing except this
|
|
15
|
+
* counter bounds HOW MUCH they can push once they satisfy it - and unbounded
|
|
16
|
+
* write volume into a customer's project is poisoned dashboards, forged spans
|
|
17
|
+
* and, on a metered plan, their bill.
|
|
18
|
+
*
|
|
19
|
+
* Four properties decide whether that ceiling is real, and each is a silent
|
|
20
|
+
* failure if it regresses:
|
|
21
|
+
*
|
|
22
|
+
* 1. Off-by-one. The Nth request in a window of N must be ADMITTED; only
|
|
23
|
+
* N + 1 is refused. A limiter that refuses the Nth quietly sells every
|
|
24
|
+
* customer one request per minute less than the number on their key.
|
|
25
|
+
* 2. EXPIRE is issued ONLY on the write that created the counter. Re-issued
|
|
26
|
+
* on every increment it slides the TTL forward for as long as the load
|
|
27
|
+
* continues, so a fixed window under sustained traffic NEVER resets - a
|
|
28
|
+
* key that tripped its limit once can never recover, which is exactly the
|
|
29
|
+
* state an attacker's loop produces. Pinned here on the mock call counts,
|
|
30
|
+
* because it is invisible from the return value.
|
|
31
|
+
* 3. The counter keeps incrementing on REJECTED requests. Being refused must
|
|
32
|
+
* not hand the hammering client a fresh allowance.
|
|
33
|
+
* 4. It FAILS OPEN. No Redis client, a disconnected Redis, or an INCR that
|
|
34
|
+
* throws all resolve to CounterUnavailable and never propagate - the
|
|
35
|
+
* caller admits the request. Failing closed would turn a Redis blip into
|
|
36
|
+
* permanent, unreplayable telemetry loss for every paying customer at the
|
|
37
|
+
* moment their dashboards are needed most.
|
|
38
|
+
*
|
|
39
|
+
* Date.now is pinned throughout so the minute bucket and the retry-after are
|
|
40
|
+
* facts of the test rather than of whichever second of the real minute the
|
|
41
|
+
* suite happened to run in. Redis is mocked at the module boundary: nothing
|
|
42
|
+
* here touches a real Redis, a real Postgres or the network.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
jest.mock("../../../../Server/Infrastructure/Redis", () => {
|
|
46
|
+
return {
|
|
47
|
+
__esModule: true,
|
|
48
|
+
default: {
|
|
49
|
+
getClient: jest.fn(),
|
|
50
|
+
isConnected: jest.fn(),
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
jest.mock("../../../../Server/Utils/Logger", () => {
|
|
56
|
+
return {
|
|
57
|
+
__esModule: true,
|
|
58
|
+
default: {
|
|
59
|
+
debug: jest.fn(),
|
|
60
|
+
info: jest.fn(),
|
|
61
|
+
warn: jest.fn(),
|
|
62
|
+
error: jest.fn(),
|
|
63
|
+
},
|
|
64
|
+
getLogAttributesFromRequest: jest.fn().mockReturnValue({}),
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
import Redis from "../../../../Server/Infrastructure/Redis";
|
|
69
|
+
import logger from "../../../../Server/Utils/Logger";
|
|
70
|
+
import TelemetryIngestionKeyRateLimiter, {
|
|
71
|
+
TelemetryIngestionKeyLimitDecision,
|
|
72
|
+
TelemetryIngestionKeyLimitOutcome,
|
|
73
|
+
} from "../../../../Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter";
|
|
74
|
+
import ObjectID from "../../../../Types/ObjectID";
|
|
75
|
+
|
|
76
|
+
type MockedFn = ReturnType<typeof jest.fn>;
|
|
77
|
+
|
|
78
|
+
const getClientMock: MockedFn = Redis.getClient as unknown as MockedFn;
|
|
79
|
+
const isConnectedMock: MockedFn = Redis.isConnected as unknown as MockedFn;
|
|
80
|
+
const loggerErrorMock: MockedFn = logger.error as unknown as MockedFn;
|
|
81
|
+
|
|
82
|
+
/* Constants baked into the limiter, named once so a change is a deliberate edit here too. */
|
|
83
|
+
const RATE_KEY_PREFIX: string = "telemetry:ingestkey:rate:";
|
|
84
|
+
const RATE_TTL_SECONDS: number = 120;
|
|
85
|
+
const WINDOW_MS: number = 60000;
|
|
86
|
+
|
|
87
|
+
interface RecordedExpire {
|
|
88
|
+
key: string;
|
|
89
|
+
ttlSeconds: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/*
|
|
93
|
+
* A fake that behaves like a Redis counter rather than a bag of assertions:
|
|
94
|
+
* INCR really increments and EXPIRE really records a TTL, so the window and
|
|
95
|
+
* pinning tests exercise the limiter's arithmetic instead of restating it.
|
|
96
|
+
*/
|
|
97
|
+
class FakeRedisClient {
|
|
98
|
+
public counters: Map<string, number> = new Map();
|
|
99
|
+
public incrKeys: Array<string> = [];
|
|
100
|
+
public expires: Array<RecordedExpire> = [];
|
|
101
|
+
|
|
102
|
+
/* Set to make the next incr() reject, for the fail-open tests. */
|
|
103
|
+
public failNextIncr: Error | null = null;
|
|
104
|
+
|
|
105
|
+
public async incr(key: string): Promise<number> {
|
|
106
|
+
this.incrKeys.push(key);
|
|
107
|
+
|
|
108
|
+
if (this.failNextIncr) {
|
|
109
|
+
const error: Error = this.failNextIncr;
|
|
110
|
+
this.failNextIncr = null;
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const next: number = (this.counters.get(key) || 0) + 1;
|
|
115
|
+
this.counters.set(key, next);
|
|
116
|
+
|
|
117
|
+
return next;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public async expire(key: string, ttlSeconds: number): Promise<number> {
|
|
121
|
+
this.expires.push({ key, ttlSeconds });
|
|
122
|
+
|
|
123
|
+
return 1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public expiresForKey(key: string): Array<RecordedExpire> {
|
|
127
|
+
return this.expires.filter((recorded: RecordedExpire) => {
|
|
128
|
+
return recorded.key === key;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
describe("TelemetryIngestionKeyRateLimiter", () => {
|
|
134
|
+
const KEY_ID: ObjectID = new ObjectID("11111111-1111-1111-1111-111111111111");
|
|
135
|
+
const OTHER_KEY_ID: ObjectID = new ObjectID(
|
|
136
|
+
"22222222-2222-2222-2222-222222222222",
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
let client: FakeRedisClient;
|
|
140
|
+
let nowSpy: ReturnType<typeof jest.spyOn>;
|
|
141
|
+
let currentTime: number;
|
|
142
|
+
|
|
143
|
+
beforeEach(() => {
|
|
144
|
+
jest.clearAllMocks();
|
|
145
|
+
|
|
146
|
+
client = new FakeRedisClient();
|
|
147
|
+
getClientMock.mockReturnValue(client);
|
|
148
|
+
isConnectedMock.mockReturnValue(true);
|
|
149
|
+
|
|
150
|
+
/*
|
|
151
|
+
* Pinned to the exact start of a minute bucket so the bucket number and
|
|
152
|
+
* the retry-after are deterministic. Tests that care about where in the
|
|
153
|
+
* window they sit move it themselves.
|
|
154
|
+
*/
|
|
155
|
+
currentTime = 1_700_000_000_000;
|
|
156
|
+
currentTime = currentTime - (currentTime % WINDOW_MS);
|
|
157
|
+
|
|
158
|
+
nowSpy = jest.spyOn(Date, "now").mockImplementation(() => {
|
|
159
|
+
return currentTime;
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
afterEach(() => {
|
|
164
|
+
nowSpy.mockRestore();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const consume: (data: {
|
|
168
|
+
ingestionKeyId?: ObjectID;
|
|
169
|
+
limitPerMinute?: number;
|
|
170
|
+
}) => Promise<TelemetryIngestionKeyLimitDecision> = (data: {
|
|
171
|
+
ingestionKeyId?: ObjectID;
|
|
172
|
+
limitPerMinute?: number;
|
|
173
|
+
}): Promise<TelemetryIngestionKeyLimitDecision> => {
|
|
174
|
+
return TelemetryIngestionKeyRateLimiter.consume({
|
|
175
|
+
ingestionKeyId: data.ingestionKeyId || KEY_ID,
|
|
176
|
+
limitPerMinute:
|
|
177
|
+
typeof data.limitPerMinute === "number" ? data.limitPerMinute : 10,
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const expectedKeyFor: (keyId: ObjectID, atMs: number) => string = (
|
|
182
|
+
keyId: ObjectID,
|
|
183
|
+
atMs: number,
|
|
184
|
+
): string => {
|
|
185
|
+
return `${RATE_KEY_PREFIX}${keyId.toString()}:${Math.floor(
|
|
186
|
+
atMs / WINDOW_MS,
|
|
187
|
+
)}`;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
describe("the allowance boundary", () => {
|
|
191
|
+
test("admits a request under the limit and gives it no retry-after", async () => {
|
|
192
|
+
const decision: TelemetryIngestionKeyLimitDecision = await consume({
|
|
193
|
+
limitPerMinute: 10,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
expect(decision.outcome).toBe(TelemetryIngestionKeyLimitOutcome.Allowed);
|
|
197
|
+
expect(decision.retryAfterSeconds).toBeUndefined();
|
|
198
|
+
expect(decision.isFirstRejectionInWindow).toBeUndefined();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
/*
|
|
202
|
+
* The off-by-one. A limit of N means N requests get through, so the Nth
|
|
203
|
+
* must be Allowed.
|
|
204
|
+
*/
|
|
205
|
+
test("admits the Nth request in a window of N", async () => {
|
|
206
|
+
const limit: number = 5;
|
|
207
|
+
const outcomes: Array<TelemetryIngestionKeyLimitOutcome> = [];
|
|
208
|
+
|
|
209
|
+
for (let index: number = 0; index < limit; index++) {
|
|
210
|
+
const decision: TelemetryIngestionKeyLimitDecision = await consume({
|
|
211
|
+
limitPerMinute: limit,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
outcomes.push(decision.outcome);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
expect(outcomes).toEqual([
|
|
218
|
+
TelemetryIngestionKeyLimitOutcome.Allowed,
|
|
219
|
+
TelemetryIngestionKeyLimitOutcome.Allowed,
|
|
220
|
+
TelemetryIngestionKeyLimitOutcome.Allowed,
|
|
221
|
+
TelemetryIngestionKeyLimitOutcome.Allowed,
|
|
222
|
+
TelemetryIngestionKeyLimitOutcome.Allowed,
|
|
223
|
+
]);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("refuses the N+1th request in a window of N", async () => {
|
|
227
|
+
const limit: number = 5;
|
|
228
|
+
|
|
229
|
+
for (let index: number = 0; index < limit; index++) {
|
|
230
|
+
await consume({ limitPerMinute: limit });
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const decision: TelemetryIngestionKeyLimitDecision = await consume({
|
|
234
|
+
limitPerMinute: limit,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
expect(decision.outcome).toBe(
|
|
238
|
+
TelemetryIngestionKeyLimitOutcome.RateLimited,
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
/*
|
|
243
|
+
* Sampled at several offsets into the window, including both edges, so a
|
|
244
|
+
* constant that happens to fall in range cannot pass this.
|
|
245
|
+
*/
|
|
246
|
+
test("tells a refused caller to come back within the minute, never sooner than a second", async () => {
|
|
247
|
+
const windowStart: number =
|
|
248
|
+
1_700_000_000_000 - (1_700_000_000_000 % WINDOW_MS);
|
|
249
|
+
|
|
250
|
+
const offsetsIntoWindow: Array<number> = [
|
|
251
|
+
0, 1, 999, 30_000, 59_000, 59_999,
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
for (const offset of offsetsIntoWindow) {
|
|
255
|
+
client = new FakeRedisClient();
|
|
256
|
+
getClientMock.mockReturnValue(client);
|
|
257
|
+
currentTime = windowStart + offset;
|
|
258
|
+
|
|
259
|
+
await consume({ limitPerMinute: 1 });
|
|
260
|
+
|
|
261
|
+
const decision: TelemetryIngestionKeyLimitDecision = await consume({
|
|
262
|
+
limitPerMinute: 1,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
expect(decision.outcome).toBe(
|
|
266
|
+
TelemetryIngestionKeyLimitOutcome.RateLimited,
|
|
267
|
+
);
|
|
268
|
+
expect(decision.retryAfterSeconds).toBeGreaterThanOrEqual(1);
|
|
269
|
+
expect(decision.retryAfterSeconds).toBeLessThanOrEqual(60);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
/*
|
|
274
|
+
* A non-positive or non-finite limit is a bad row or a caller bug, not a
|
|
275
|
+
* customer asking for a total blackout of their own ingest. It reads as
|
|
276
|
+
* "no limit" and short-circuits before Redis is touched.
|
|
277
|
+
*/
|
|
278
|
+
test("treats a non-positive or non-finite limit as no limit and never touches Redis", async () => {
|
|
279
|
+
const badLimits: Array<number> = [
|
|
280
|
+
0,
|
|
281
|
+
-1,
|
|
282
|
+
Number.NaN,
|
|
283
|
+
Number.POSITIVE_INFINITY,
|
|
284
|
+
];
|
|
285
|
+
|
|
286
|
+
for (const limit of badLimits) {
|
|
287
|
+
const decision: TelemetryIngestionKeyLimitDecision = await consume({
|
|
288
|
+
limitPerMinute: limit,
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
expect(decision.outcome).toBe(
|
|
292
|
+
TelemetryIngestionKeyLimitOutcome.Allowed,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
expect(client.incrKeys).toHaveLength(0);
|
|
297
|
+
expect(getClientMock).not.toHaveBeenCalled();
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
describe("the fixed window does not slide", () => {
|
|
302
|
+
/*
|
|
303
|
+
* THE bug this suite exists for. EXPIRE belongs only on the write that
|
|
304
|
+
* created the counter; issued on every increment it pushes the TTL out for
|
|
305
|
+
* as long as traffic continues, so the window never rolls and a key that
|
|
306
|
+
* tripped its limit once under load stays refused forever.
|
|
307
|
+
*/
|
|
308
|
+
test("issues EXPIRE only on the write that created the counter", async () => {
|
|
309
|
+
const limit: number = 3;
|
|
310
|
+
|
|
311
|
+
for (let index: number = 0; index < 10; index++) {
|
|
312
|
+
await consume({ limitPerMinute: limit });
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const key: string = expectedKeyFor(KEY_ID, currentTime);
|
|
316
|
+
|
|
317
|
+
expect(client.incrKeys).toHaveLength(10);
|
|
318
|
+
expect(client.expiresForKey(key)).toHaveLength(1);
|
|
319
|
+
expect(client.expiresForKey(key)[0]?.ttlSeconds).toBe(RATE_TTL_SECONDS);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
test("issues EXPIRE once more for the next window's own counter", async () => {
|
|
323
|
+
await consume({ limitPerMinute: 3 });
|
|
324
|
+
await consume({ limitPerMinute: 3 });
|
|
325
|
+
|
|
326
|
+
const firstKey: string = expectedKeyFor(KEY_ID, currentTime);
|
|
327
|
+
|
|
328
|
+
currentTime = currentTime + WINDOW_MS;
|
|
329
|
+
|
|
330
|
+
await consume({ limitPerMinute: 3 });
|
|
331
|
+
await consume({ limitPerMinute: 3 });
|
|
332
|
+
|
|
333
|
+
const secondKey: string = expectedKeyFor(KEY_ID, currentTime);
|
|
334
|
+
|
|
335
|
+
expect(secondKey).not.toBe(firstKey);
|
|
336
|
+
expect(client.expiresForKey(firstKey)).toHaveLength(1);
|
|
337
|
+
expect(client.expiresForKey(secondKey)).toHaveLength(1);
|
|
338
|
+
expect(client.expires).toHaveLength(2);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test("hands the key a fresh allowance once the minute bucket rolls", async () => {
|
|
342
|
+
const limit: number = 2;
|
|
343
|
+
|
|
344
|
+
await consume({ limitPerMinute: limit });
|
|
345
|
+
await consume({ limitPerMinute: limit });
|
|
346
|
+
|
|
347
|
+
const refused: TelemetryIngestionKeyLimitDecision = await consume({
|
|
348
|
+
limitPerMinute: limit,
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
expect(refused.outcome).toBe(
|
|
352
|
+
TelemetryIngestionKeyLimitOutcome.RateLimited,
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
currentTime = currentTime + WINDOW_MS;
|
|
356
|
+
|
|
357
|
+
const afterRoll: TelemetryIngestionKeyLimitDecision = await consume({
|
|
358
|
+
limitPerMinute: limit,
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
expect(afterRoll.outcome).toBe(TelemetryIngestionKeyLimitOutcome.Allowed);
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
/*
|
|
365
|
+
* Standard fixed-window behaviour, and the point of it: a client hammering
|
|
366
|
+
* a scraped key keeps its own window pinned rather than being handed a
|
|
367
|
+
* fresh allowance for free by virtue of having been refused.
|
|
368
|
+
*/
|
|
369
|
+
test("keeps counting rejected requests, so hammering does not buy a fresh allowance", async () => {
|
|
370
|
+
const limit: number = 1;
|
|
371
|
+
const key: string = expectedKeyFor(KEY_ID, currentTime);
|
|
372
|
+
|
|
373
|
+
await consume({ limitPerMinute: limit });
|
|
374
|
+
|
|
375
|
+
for (let index: number = 0; index < 5; index++) {
|
|
376
|
+
const decision: TelemetryIngestionKeyLimitDecision = await consume({
|
|
377
|
+
limitPerMinute: limit,
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
expect(decision.outcome).toBe(
|
|
381
|
+
TelemetryIngestionKeyLimitOutcome.RateLimited,
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
expect(client.counters.get(key)).toBe(6);
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
describe("counter keying", () => {
|
|
390
|
+
test("keys the counter on the ingestion key id and the current minute bucket", async () => {
|
|
391
|
+
await consume({ limitPerMinute: 10 });
|
|
392
|
+
|
|
393
|
+
expect(client.incrKeys).toEqual([
|
|
394
|
+
`${RATE_KEY_PREFIX}${KEY_ID.toString()}:${currentTime / WINDOW_MS}`,
|
|
395
|
+
]);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
test("does not let two ingestion keys share a counter", async () => {
|
|
399
|
+
const limit: number = 1;
|
|
400
|
+
|
|
401
|
+
await consume({ ingestionKeyId: KEY_ID, limitPerMinute: limit });
|
|
402
|
+
|
|
403
|
+
const sameKeyAgain: TelemetryIngestionKeyLimitDecision = await consume({
|
|
404
|
+
ingestionKeyId: KEY_ID,
|
|
405
|
+
limitPerMinute: limit,
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
const otherKey: TelemetryIngestionKeyLimitDecision = await consume({
|
|
409
|
+
ingestionKeyId: OTHER_KEY_ID,
|
|
410
|
+
limitPerMinute: limit,
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
expect(sameKeyAgain.outcome).toBe(
|
|
414
|
+
TelemetryIngestionKeyLimitOutcome.RateLimited,
|
|
415
|
+
);
|
|
416
|
+
expect(otherKey.outcome).toBe(TelemetryIngestionKeyLimitOutcome.Allowed);
|
|
417
|
+
expect(client.counters.get(expectedKeyFor(KEY_ID, currentTime))).toBe(2);
|
|
418
|
+
expect(
|
|
419
|
+
client.counters.get(expectedKeyFor(OTHER_KEY_ID, currentTime)),
|
|
420
|
+
).toBe(1);
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
describe("first rejection in the window", () => {
|
|
425
|
+
/*
|
|
426
|
+
* A refused caller keeps knocking, so a caller that logged every refusal
|
|
427
|
+
* would answer an ingest flood with a log flood. Exactly one line per key
|
|
428
|
+
* per minute is what an operator needs to see WHICH key is being abused.
|
|
429
|
+
*/
|
|
430
|
+
test("marks only the request that crossed the line", async () => {
|
|
431
|
+
const limit: number = 2;
|
|
432
|
+
|
|
433
|
+
await consume({ limitPerMinute: limit });
|
|
434
|
+
await consume({ limitPerMinute: limit });
|
|
435
|
+
|
|
436
|
+
const first: TelemetryIngestionKeyLimitDecision = await consume({
|
|
437
|
+
limitPerMinute: limit,
|
|
438
|
+
});
|
|
439
|
+
const second: TelemetryIngestionKeyLimitDecision = await consume({
|
|
440
|
+
limitPerMinute: limit,
|
|
441
|
+
});
|
|
442
|
+
const third: TelemetryIngestionKeyLimitDecision = await consume({
|
|
443
|
+
limitPerMinute: limit,
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
expect(first.isFirstRejectionInWindow).toBe(true);
|
|
447
|
+
expect(second.isFirstRejectionInWindow).toBe(false);
|
|
448
|
+
expect(third.isFirstRejectionInWindow).toBe(false);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
test("marks the crossing again in the next window", async () => {
|
|
452
|
+
const limit: number = 1;
|
|
453
|
+
|
|
454
|
+
await consume({ limitPerMinute: limit });
|
|
455
|
+
await consume({ limitPerMinute: limit });
|
|
456
|
+
|
|
457
|
+
currentTime = currentTime + WINDOW_MS;
|
|
458
|
+
|
|
459
|
+
await consume({ limitPerMinute: limit });
|
|
460
|
+
|
|
461
|
+
const crossing: TelemetryIngestionKeyLimitDecision = await consume({
|
|
462
|
+
limitPerMinute: limit,
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
expect(crossing.outcome).toBe(
|
|
466
|
+
TelemetryIngestionKeyLimitOutcome.RateLimited,
|
|
467
|
+
);
|
|
468
|
+
expect(crossing.isFirstRejectionInWindow).toBe(true);
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
describe("fails open when the counter is unavailable", () => {
|
|
473
|
+
test("reports CounterUnavailable when there is no Redis client", async () => {
|
|
474
|
+
getClientMock.mockReturnValue(null);
|
|
475
|
+
|
|
476
|
+
const decision: TelemetryIngestionKeyLimitDecision = await consume({
|
|
477
|
+
limitPerMinute: 1,
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
expect(decision.outcome).toBe(
|
|
481
|
+
TelemetryIngestionKeyLimitOutcome.CounterUnavailable,
|
|
482
|
+
);
|
|
483
|
+
expect(decision.retryAfterSeconds).toBeUndefined();
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
test("reports CounterUnavailable when Redis is not connected", async () => {
|
|
487
|
+
isConnectedMock.mockReturnValue(false);
|
|
488
|
+
|
|
489
|
+
const decision: TelemetryIngestionKeyLimitDecision = await consume({
|
|
490
|
+
limitPerMinute: 1,
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
expect(decision.outcome).toBe(
|
|
494
|
+
TelemetryIngestionKeyLimitOutcome.CounterUnavailable,
|
|
495
|
+
);
|
|
496
|
+
expect(client.incrKeys).toHaveLength(0);
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
test("swallows a failing INCR rather than letting it reach the ingest route", async () => {
|
|
500
|
+
client.failNextIncr = new Error(
|
|
501
|
+
"READONLY You can't write against a read only replica.",
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
const decision: TelemetryIngestionKeyLimitDecision = await consume({
|
|
505
|
+
limitPerMinute: 1,
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
expect(decision.outcome).toBe(
|
|
509
|
+
TelemetryIngestionKeyLimitOutcome.CounterUnavailable,
|
|
510
|
+
);
|
|
511
|
+
expect(loggerErrorMock).not.toHaveBeenCalled();
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
test("counts normally again on the request after a transient INCR failure", async () => {
|
|
515
|
+
client.failNextIncr = new Error("connection reset by peer");
|
|
516
|
+
|
|
517
|
+
await consume({ limitPerMinute: 1 });
|
|
518
|
+
|
|
519
|
+
const afterRecovery: TelemetryIngestionKeyLimitDecision = await consume({
|
|
520
|
+
limitPerMinute: 1,
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
expect(afterRecovery.outcome).toBe(
|
|
524
|
+
TelemetryIngestionKeyLimitOutcome.Allowed,
|
|
525
|
+
);
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test } from "@jest/globals";
|
|
2
|
+
import Telemetry from "../../../Server/Utils/Telemetry";
|
|
3
|
+
|
|
4
|
+
const originalEnv: NodeJS.ProcessEnv = { ...process.env };
|
|
5
|
+
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
process.env = { ...originalEnv };
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
describe("server telemetry exporter environment", () => {
|
|
11
|
+
test("continues to read generic backend exporter headers", () => {
|
|
12
|
+
process.env["OPENTELEMETRY_EXPORTER_OTLP_HEADERS"] =
|
|
13
|
+
"authorization=Bearer server-secret;x-oneuptime-token=server-key";
|
|
14
|
+
|
|
15
|
+
expect(Telemetry.getHeaders()).toEqual({
|
|
16
|
+
authorization: "Bearer server-secret",
|
|
17
|
+
"x-oneuptime-token": "server-key",
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("does not treat the public Browser key as server authorization", () => {
|
|
22
|
+
delete process.env["OPENTELEMETRY_EXPORTER_OTLP_HEADERS"];
|
|
23
|
+
process.env["PUBLIC_OPENTELEMETRY_EXPORTER_OTLP_BROWSER_INGESTION_KEY"] =
|
|
24
|
+
"public-browser-key";
|
|
25
|
+
|
|
26
|
+
expect(Telemetry.getHeaders()).toEqual({});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("returns no backend headers for an unset or blank value", () => {
|
|
30
|
+
delete process.env["OPENTELEMETRY_EXPORTER_OTLP_HEADERS"];
|
|
31
|
+
expect(Telemetry.getHeaders()).toEqual({});
|
|
32
|
+
|
|
33
|
+
process.env["OPENTELEMETRY_EXPORTER_OTLP_HEADERS"] = "";
|
|
34
|
+
expect(Telemetry.getHeaders()).toEqual({});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("continues to read the generic backend exporter endpoint", () => {
|
|
38
|
+
process.env["OPENTELEMETRY_EXPORTER_OTLP_ENDPOINT"] =
|
|
39
|
+
"https://collector.internal:4318";
|
|
40
|
+
|
|
41
|
+
expect(Telemetry.getOtlpEndpoint()?.toString()).toBe(
|
|
42
|
+
"https://collector.internal:4318/",
|
|
43
|
+
);
|
|
44
|
+
expect(Telemetry.getOltpTracesEndpoint()?.toString()).toBe(
|
|
45
|
+
"https://collector.internal:4318/v1/traces",
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("does not use the public browser endpoint as the server endpoint", () => {
|
|
50
|
+
delete process.env["OPENTELEMETRY_EXPORTER_OTLP_ENDPOINT"];
|
|
51
|
+
process.env["PUBLIC_OPENTELEMETRY_EXPORTER_OTLP_ENDPOINT"] =
|
|
52
|
+
"https://browser-collector.example.com:4318";
|
|
53
|
+
|
|
54
|
+
expect(Telemetry.getOtlpEndpoint()).toBeNull();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import VMRunner from "../../../../Server/Utils/VM/VMRunner";
|
|
2
|
+
import ReturnResult from "../../../../Types/IsolatedVM/ReturnResult";
|
|
3
|
+
import { describe, expect, test } from "@jest/globals";
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* Regression guard for the host-bridge stall.
|
|
7
|
+
*
|
|
8
|
+
* Every bridge the sandbox has - axios, sleep, the log sink - is an
|
|
9
|
+
* isolated-vm async callback: the isolate posts a call onto Node's thread,
|
|
10
|
+
* Node answers it, and the isolate resumes. Each hop only advances when the
|
|
11
|
+
* event loop takes a turn, and a loop with nothing else pending sleeps until
|
|
12
|
+
* its NEXT TIMER rather than turning again.
|
|
13
|
+
*
|
|
14
|
+
* Without a ticker to wake it, the nearest timer was usually the sandbox's own
|
|
15
|
+
* 20s overall timeout, so `await sleep(0)` - and a request the SSRF guard
|
|
16
|
+
* refuses synchronously, in microseconds - came back twenty seconds later as
|
|
17
|
+
* "Script execution timed out". That is what failed the VMRunner SSRF suite on
|
|
18
|
+
* CI while it passed on a developer's machine, where an editor or a watcher
|
|
19
|
+
* happened to keep the loop busy.
|
|
20
|
+
*
|
|
21
|
+
* The budget below is deliberately loose. A fixed run measures single-digit
|
|
22
|
+
* milliseconds per round trip; the regression measured hundreds to twenty
|
|
23
|
+
* thousand. Anything between leaves this test alone.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const ROUND_TRIPS: number = 12;
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* Generous enough to absorb a loaded CI runner (the fixed path needs ~10ms per
|
|
30
|
+
* run), tight enough that the stall - which costs at least 100ms per run, and
|
|
31
|
+
* routinely a full second - cannot fit inside it.
|
|
32
|
+
*/
|
|
33
|
+
const BUDGET_MS: number = 3000;
|
|
34
|
+
|
|
35
|
+
describe("VMRunner host bridge latency", () => {
|
|
36
|
+
test("a sandbox round trip does not wait for an unrelated timer", async () => {
|
|
37
|
+
const started: number = Date.now();
|
|
38
|
+
|
|
39
|
+
for (let index: number = 0; index < ROUND_TRIPS; index++) {
|
|
40
|
+
const result: ReturnResult = await VMRunner.runCodeInSandbox({
|
|
41
|
+
code: "await sleep(0); return 'done';",
|
|
42
|
+
options: { timeout: 15000 },
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
/* The point is that it finished at all, quickly, and with an answer. */
|
|
46
|
+
expect(result.scriptError).toBeUndefined();
|
|
47
|
+
expect(result.returnValue).toBe("done");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const elapsed: number = Date.now() - started;
|
|
51
|
+
|
|
52
|
+
expect(elapsed).toBeLessThan(BUDGET_MS);
|
|
53
|
+
}, 60000);
|
|
54
|
+
|
|
55
|
+
test("a request the guard refuses comes back without a host round-trip stall", async () => {
|
|
56
|
+
const started: number = Date.now();
|
|
57
|
+
|
|
58
|
+
for (let index: number = 0; index < ROUND_TRIPS; index++) {
|
|
59
|
+
const result: ReturnResult = await VMRunner.runCodeInSandbox({
|
|
60
|
+
/*
|
|
61
|
+
* Protocol-relative, so resolveEffectiveRequestUrl rejects it before
|
|
62
|
+
* DNS or a socket: the only cost here is the isolate <-> host hops.
|
|
63
|
+
*/
|
|
64
|
+
code: "try { return await axios.get('//169.254.169.254/latest/meta-data/'); } catch (error) { return 'refused'; }",
|
|
65
|
+
options: { timeout: 15000 },
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
expect(result.scriptError).toBeUndefined();
|
|
69
|
+
expect(result.returnValue).toBe("refused");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
expect(Date.now() - started).toBeLessThan(BUDGET_MS);
|
|
73
|
+
}, 60000);
|
|
74
|
+
});
|