@oneuptime/common 12.0.32 → 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/AnalyticsModels/Span.ts +14 -0
- package/Models/DatabaseModels/AlertCustomField.ts +77 -3
- package/Models/DatabaseModels/ApiKeyPermission.ts +3 -27
- package/Models/DatabaseModels/EnterpriseLicense.ts +56 -0
- package/Models/DatabaseModels/IncidentCustomField.ts +77 -3
- package/Models/DatabaseModels/Index.ts +10 -0
- package/Models/DatabaseModels/InventoryItemCustomField.ts +77 -3
- package/Models/DatabaseModels/Monitor.ts +76 -0
- package/Models/DatabaseModels/MonitorCustomField.ts +77 -3
- package/Models/DatabaseModels/NetworkAlertPolicy.ts +690 -0
- package/Models/DatabaseModels/NetworkDevice.ts +176 -1
- package/Models/DatabaseModels/NetworkSite.ts +201 -2
- package/Models/DatabaseModels/NetworkSiteType.ts +102 -3
- package/Models/DatabaseModels/NetworkSnmpCredentialProfile.ts +841 -0
- 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/TelemetryException.ts +119 -0
- package/Models/DatabaseModels/TelemetryIngestionKey.ts +260 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupBatch.ts +334 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +370 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupSetting.ts +282 -0
- package/Models/DatabaseModels/UserTelegram.ts +0 -4
- package/Scripts/benchmark-fanin-capacity.js +181 -0
- package/Server/API/EnterpriseLicenseAPI.ts +391 -64
- package/Server/API/LlmProviderAPI.ts +137 -22
- 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 +49 -2
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.ts +55 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.ts +124 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.ts +132 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.ts +79 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.ts +191 -0
- 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 +20 -0
- package/Server/Infrastructure/QueueWorker.ts +59 -23
- package/Server/Infrastructure/Semaphore.ts +2 -0
- package/Server/Middleware/BearerTokenAuthorization.ts +12 -0
- package/Server/Middleware/ProjectAuthorization.ts +11 -0
- package/Server/Middleware/SCIMAuthorization.ts +12 -0
- package/Server/Middleware/TelemetryIngest.ts +464 -7
- package/Server/Services/AIBillingService.ts +101 -27
- 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/EnterpriseLicenseInstanceService.ts +197 -0
- package/Server/Services/EnterpriseLicenseService.ts +55 -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/Index.ts +10 -0
- package/Server/Services/MetricService.ts +194 -0
- package/Server/Services/MonitorService.ts +175 -21
- package/Server/Services/MonitorStatusTimelineService.ts +150 -8
- package/Server/Services/MonitorTemplateService.ts +217 -1
- package/Server/Services/NetworkAlertPolicyEngineService.ts +2159 -0
- package/Server/Services/NetworkAlertPolicyService.ts +944 -0
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +87 -35
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +60 -15
- package/Server/Services/NetworkDeviceService.ts +1032 -73
- package/Server/Services/NetworkSiteService.ts +1502 -129
- package/Server/Services/NetworkSiteTypeService.ts +1216 -0
- package/Server/Services/NetworkSnmpCredentialProfileService.ts +238 -0
- package/Server/Services/NotificationService.ts +118 -28
- package/Server/Services/ProjectService.ts +127 -48
- 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/StatusPagePrivateUserService.ts +103 -3
- package/Server/Services/TeamMemberService.ts +78 -0
- package/Server/Services/TeamPermissionService.ts +235 -3
- package/Server/Services/TelemetryIngestionKeyService.ts +722 -19
- package/Server/Services/UserNotificationEmailRollupBatchService.ts +78 -0
- package/Server/Services/UserNotificationEmailRollupItemService.ts +79 -0
- package/Server/Services/UserNotificationEmailRollupSettingService.ts +113 -0
- package/Server/Services/UserNotificationSettingService.ts +90 -25
- package/Server/Services/UserService.ts +95 -0
- package/Server/Services/UserTelegramService.ts +326 -5
- package/Server/Types/Database/QueryHelper.ts +4 -2
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +14 -3
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +10 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +10 -0
- package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +62 -1
- package/Server/Utils/AI/Toolbox/AlertTools.ts +15 -1
- package/Server/Utils/APIKey/AccessPermission.ts +5 -2
- package/Server/Utils/Billing/BillingFailureNoticeThrottle.ts +80 -0
- 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/DataSource/HttpFetch.ts +9 -2
- package/Server/Utils/EmailRollup/EmailRollupConstants.ts +131 -0
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +925 -0
- package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +781 -0
- package/Server/Utils/EmailRollup/EmailRollupWriter.ts +368 -0
- package/Server/Utils/FrontendEnvironment.ts +40 -0
- package/Server/Utils/LLM/LLMService.ts +78 -0
- package/Server/Utils/LogRedaction.ts +28 -0
- package/Server/Utils/Logger.ts +90 -1
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +338 -77
- package/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.ts +190 -0
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +9 -2
- package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +30 -4
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +61 -1
- package/Server/Utils/Monitor/MonitorAlert.ts +29 -6
- package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +159 -15
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +255 -4
- package/Server/Utils/Monitor/MonitorIncident.ts +22 -6
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +41 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +72 -0
- package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +499 -19
- package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +66 -10
- package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +238 -44
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +146 -39
- package/Server/Utils/Monitor/SeriesContextEnricher.ts +304 -0
- package/Server/Utils/NetworkDevice/DeviceHealthAggregation.ts +31 -18
- package/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.ts +213 -0
- package/Server/Utils/OutboundUserAgent.ts +152 -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 +53 -36
- package/Server/Utils/TelegramVerificationToken.ts +185 -0
- package/Server/Utils/Telemetry/CaptureSpan.ts +32 -8
- package/Server/Utils/Telemetry/ErrorClassResolver.ts +120 -0
- package/Server/Utils/Telemetry/PinServiceName.ts +197 -0
- package/Server/Utils/Telemetry/SpanUtil.ts +33 -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/Telemetry.ts +198 -51
- package/Server/Utils/VM/VMAPI.ts +1 -0
- package/Server/Utils/VM/VMRunner.ts +975 -95
- package/Server/Views/Partials/SensitiveUrlToken.ejs +140 -0
- package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +202 -0
- package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +134 -33
- package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +279 -0
- package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +517 -0
- package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +404 -0
- package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +26 -0
- package/Tests/App/Dashboard/DeviceStatusHero.test.tsx +588 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +486 -9
- package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +632 -0
- package/Tests/App/Dashboard/MonitorRecommendationCreateProgress.test.tsx +682 -0
- package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +4 -2
- package/Tests/App/Dashboard/NetworkDeviceCreateFormMonitorBinding.test.tsx +676 -0
- package/Tests/App/Dashboard/NetworkDeviceCreateFormPingMonitor.test.tsx +791 -0
- package/Tests/App/Dashboard/NetworkDeviceCreateFormProbeAndSnmp.test.tsx +833 -0
- package/Tests/App/Dashboard/NetworkDeviceCriteriaFilter.test.ts +161 -0
- package/Tests/App/Dashboard/NetworkDeviceSettingsMonitoringSection.test.tsx +458 -0
- package/Tests/App/Dashboard/NetworkSideMenu.test.tsx +41 -5
- package/Tests/App/Dashboard/NotificationEmailPreferences.test.tsx +399 -0
- package/Tests/App/Dashboard/PingMonitorProvisioning.test.ts +368 -0
- package/Tests/App/Dashboard/RecommendationCard.test.tsx +796 -0
- package/Tests/App/Dashboard/RecommendationToolbar.test.tsx +519 -0
- package/Tests/App/Dashboard/RecommendationsList.test.tsx +661 -0
- package/Tests/App/Dashboard/UseBulkCreatePingMonitors.test.tsx +899 -0
- package/Tests/App/Dashboard/UseBulkSnmpCredentialProfileActions.test.tsx +732 -0
- package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +256 -0
- package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +11 -1
- package/Tests/App/StatusPage/StatusPageLastUpdated.test.tsx +263 -0
- package/Tests/App/StatusPage/StatusPageLoginCodeBootstrap.test.ts +9 -4
- 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/Models/NetworkSiteHierarchy.test.ts +41 -4
- package/Tests/ResponsiveVisibility.test.ts +115 -0
- package/Tests/ResponsiveVisibility.ts +183 -0
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +951 -7
- package/Tests/Server/API/LlmProviderConnectionTest.test.ts +522 -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/NetworkSnmpCredentialProfilesAndAlertPoliciesMigration.test.ts +854 -0
- package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +18 -0
- package/Tests/Server/Infrastructure/Postgres/SessionReplayRecordEverySessionByDefaultMigration.test.ts +169 -0
- package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +535 -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/AIChatPrivacyPin.test.ts +560 -0
- 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/BillingRechargeOwnerEmailGuards.test.ts +783 -0
- 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/EnterpriseLicenseInstanceServiceDeletionUsage.test.ts +707 -0
- package/Tests/Server/Services/EnterpriseLicenseServiceUsageAggregationLock.test.ts +329 -0
- package/Tests/Server/Services/GlobalConfigService.test.ts +414 -1
- package/Tests/Server/Services/MetricRawEntityKeyPrune.test.ts +592 -0
- package/Tests/Server/Services/MonitorServiceDeleteNetworkDeviceCleanup.test.ts +294 -0
- package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +802 -0
- package/Tests/Server/Services/MonitorStatusTimelineService.test.ts +72 -2
- package/Tests/Server/Services/NetworkAlertPolicyEngineHooks.test.ts +752 -0
- package/Tests/Server/Services/NetworkAlertPolicyEngineService.test.ts +1849 -0
- package/Tests/Server/Services/NetworkAlertPolicyModel.test.ts +1793 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +273 -5
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +97 -12
- package/Tests/Server/Services/NetworkDeviceAutoMonitorLifecycle.test.ts +148 -3
- package/Tests/Server/Services/NetworkDeviceMonitorBindingUpdateGuard.test.ts +514 -0
- package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +447 -58
- package/Tests/Server/Services/NetworkDeviceMonitoringMethodTransition.test.ts +739 -0
- package/Tests/Server/Services/NetworkDevicePollingTenancy.test.ts +501 -0
- package/Tests/Server/Services/NetworkDeviceSiteDefaultProbe.test.ts +432 -0
- package/Tests/Server/Services/NetworkSiteMonitoringDefaults.test.ts +498 -0
- package/Tests/Server/Services/NetworkSiteRollupPolicyAndMaintenance.test.ts +337 -55
- package/Tests/Server/Services/NetworkSiteService.test.ts +1868 -131
- package/Tests/Server/Services/NetworkSiteTypeService.test.ts +1109 -0
- package/Tests/Server/Services/NetworkSnmpCredentialProfileModel.test.ts +926 -0
- package/Tests/Server/Services/NetworkSnmpCredentialProfileService.test.ts +796 -0
- package/Tests/Server/Services/ProjectServiceNetworkSiteTypeDefaults.test.ts +214 -0
- package/Tests/Server/Services/RoutineEmailSettingsPostgres.test.ts +329 -0
- package/Tests/Server/Services/RumSessionReplayViewService.test.ts +267 -0
- package/Tests/Server/Services/StatusPagePrivateUserEmailChangePasswordResetExpiry.test.ts +269 -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/UserEmailChangePasswordResetExpiry.test.ts +472 -0
- package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +569 -0
- package/Tests/Server/Services/UserNotificationEmailRollupSettingModel.test.ts +314 -0
- package/Tests/Server/Services/UserNotificationEmailRollupSettingService.test.ts +409 -0
- package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +997 -0
- package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +110 -1
- package/Tests/Server/Services/UserTelegramVerificationSecurity.test.ts +688 -0
- package/Tests/Server/Types/Database/Permissions/DashboardAccessPermission.test.ts +321 -0
- package/Tests/Server/Types/Database/QueryHelperOperators.test.ts +17 -0
- package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +124 -0
- package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +208 -0
- package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +235 -0
- package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +253 -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/Captcha.test.ts +422 -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/DataSource/HttpFetch.test.ts +96 -2
- package/Tests/Server/Utils/Database/MigrationFailureLog.test.ts +466 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupBurstWindow.test.ts +83 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1096 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerClaim.test.ts +466 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerPreferences.test.ts +362 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +1428 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +828 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +864 -0
- 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/LoggerFaultDemotion.test.ts +346 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +584 -0
- package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +633 -0
- package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestHeaderCriteria.test.ts +236 -0
- package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +196 -0
- package/Tests/Server/Utils/Monitor/DatabaseMetricWrite.test.ts +367 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +437 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +100 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +5 -0
- package/Tests/Server/Utils/Monitor/MonitorTemplateUtilSeriesContext.test.ts +176 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +512 -31
- package/Tests/Server/Utils/Monitor/NetworkDeviceMetricUtil.test.ts +252 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +479 -42
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +351 -5
- package/Tests/Server/Utils/Monitor/SeriesContextEnricher.test.ts +356 -0
- package/Tests/Server/Utils/NetworkDevice/DeviceHealthAggregation.test.ts +136 -12
- package/Tests/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.test.ts +306 -0
- package/Tests/Server/Utils/OutboundUserAgent.test.ts +266 -0
- package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +595 -0
- package/Tests/Server/Utils/SecurityEvent/ThreatIntel/TaxiiClientUserAgent.test.ts +141 -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/ErrorClassResolver.test.ts +298 -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/Telemetry.test.ts +456 -66
- 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/DatabaseMetricCatalog.test.ts +388 -0
- 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/MonitorStepDatabaseMonitor.test.ts +243 -0
- package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +16 -7
- package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +60 -0
- 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/NetworkDevice/NetworkAlertPolicyScope.test.ts +655 -0
- package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +115 -26
- package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +39 -0
- package/Tests/Types/NotificationSetting/NotificationEmailRollupPolicy.test.ts +299 -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/Telemetry/ErrorClass.test.ts +483 -0
- package/Tests/Types/WebsiteRequest.test.ts +285 -3
- package/Tests/UI/Components/BasicRadioButtons.test.tsx +336 -0
- 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 +43 -12
- package/Tests/UI/Components/ProgressBar.test.tsx +38 -2
- package/Tests/UI/Components/ShortcutDialogGuard.test.tsx +74 -0
- package/Tests/UI/Components/SideMenuItem.test.tsx +226 -4
- package/Tests/UI/Components/SideMenuSection.test.tsx +310 -0
- package/Tests/UI/Components/SideOverSubmitState.test.tsx +335 -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/UI/Utils/PageScrollLock.test.tsx +377 -0
- package/Tests/UI/Utils/PermissionGate.test.ts +78 -0
- package/Tests/UI/Utils/SensitiveUrlToken.test.ts +140 -0
- package/Tests/Utils/API.test.ts +308 -0
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +69 -0
- package/Tests/Utils/EnterpriseLicenseSync.test.ts +7 -1
- package/Tests/Utils/EnterpriseLicenseUsage.test.ts +433 -2
- package/Tests/Utils/HTTPResponseBodyReader.test.ts +323 -0
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +280 -1
- package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +38 -0
- package/Tests/Utils/NetworkDevice/DeviceHealthStateUtil.test.ts +284 -23
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +177 -0
- package/Tests/Utils/NetworkDevice/MonitoringMethodThreadedClassifiers.test.ts +992 -0
- package/Tests/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.test.ts +427 -0
- package/Tests/Utils/NetworkDevice/ReachabilityStampConsistency.test.ts +185 -0
- package/Tests/Utils/NetworkDevice/SnmpCredentialUtil.test.ts +268 -0
- package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +55 -5
- package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +98 -21
- package/Tests/Utils/NetworkDiscovery/DiscoveryImportEligibility.test.ts +98 -20
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +8 -7
- package/Tests/Utils/NetworkDiscovery/DiscoveryScanStatus.test.ts +117 -0
- package/Tests/Utils/NetworkDiscovery/PingMonitorBuilderForAddress.test.ts +274 -0
- package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +230 -51
- package/Tests/Utils/NetworkSite/TypeHierarchyUtil.test.ts +209 -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/CaptureSpanExportGating.test.ts +145 -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/AI/ExceptionAIClassification.ts +10 -24
- package/Types/CustomField/CustomFieldMappingCatalog.ts +161 -0
- package/Types/CustomField/CustomFieldMappingSourceResource.ts +19 -0
- package/Types/CustomField/CustomFieldValueMapping.ts +288 -0
- package/Types/Email/EmailTemplateType.ts +2 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +5 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.ts +13 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.ts +6 -0
- package/Types/Exception/ApiException.ts +10 -0
- package/Types/Exception/BadDataException.ts +11 -0
- package/Types/Exception/BadRequestException.ts +11 -0
- package/Types/Exception/Exception.ts +65 -0
- package/Types/Exception/ForbiddenException.ts +10 -0
- package/Types/Exception/NotAuthenticatedException.ts +10 -0
- package/Types/Exception/NotAuthorizedException.ts +10 -0
- package/Types/Exception/NotFoundException.ts +11 -0
- package/Types/Exception/PayloadTooLargeException.ts +11 -0
- package/Types/Exception/PaymentRequiredException.ts +10 -0
- package/Types/Exception/ServiceUnavailableException.ts +10 -0
- package/Types/Exception/SsoAuthorizationException.ts +10 -0
- package/Types/Exception/TenantNotFoundException.ts +11 -0
- package/Types/Exception/TimeoutException.ts +10 -0
- package/Types/Exception/TooManyRequestsException.ts +10 -0
- package/Types/Exception/UnableToReachServer.ts +10 -0
- package/Types/Exception/WebsiteRequestException.ts +10 -0
- package/Types/Icon/IconProp.ts +1 -0
- package/Types/JSONFunctions.ts +189 -43
- package/Types/Monitor/CephAlertTemplates.ts +157 -195
- package/Types/Monitor/CriteriaFilter.ts +60 -2
- package/Types/Monitor/DatabaseMetricCatalog.ts +693 -0
- package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +83 -0
- 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/MonitorCriteriaInstance.ts +76 -0
- package/Types/Monitor/MonitorMetricType.ts +71 -0
- package/Types/Monitor/MonitorStep.ts +76 -0
- package/Types/Monitor/MonitorStepDatabaseMonitor.ts +171 -0
- package/Types/Monitor/MonitorStepSqlMonitor.ts +2 -20
- package/Types/Monitor/MonitorType.ts +47 -1
- 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/SnmpMonitor/NetworkDeviceAlertPack.ts +22 -1
- package/Types/Monitor/SqlConnectionConfig.ts +31 -0
- package/Types/Monitor/UptimeHistoryLabels.ts +56 -0
- package/Types/NetworkDevice/NetworkAlertPolicyScope.ts +343 -0
- package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +42 -22
- package/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.ts +30 -0
- package/Types/NotificationSetting/NotificationEmailRollupCategory.ts +255 -0
- package/Types/NotificationSetting/NotificationEmailRollupPolicy.ts +104 -0
- package/Types/NotificationSetting/RoutineEmailEvents.ts +30 -0
- package/Types/Permission.ts +90 -0
- package/Types/Probe/ProbeMonitorResponse.ts +16 -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/ErrorClass.ts +274 -0
- package/Types/Telemetry/TelemetryIngestSurface.ts +95 -0
- package/Types/Telemetry/TelemetryIngestionKeyPolicy.ts +75 -0
- package/Types/Telemetry/TelemetryIngestionKeyType.ts +29 -0
- package/Types/Telemetry/UnitOfWork.ts +59 -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/CommandPalette/CommandPalette.tsx +2 -8
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +143 -25
- package/UI/Components/CustomFields/MapFromCustomFieldInput.tsx +216 -0
- package/UI/Components/EditionLabel/EditionLabel.tsx +4 -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/Modal/Modal.tsx +2 -8
- 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 +88 -0
- package/UI/Components/ProgressBar/ProgressBar.tsx +12 -1
- package/UI/Components/RadioButtons/BasicRadioButtons.tsx +37 -7
- package/UI/Components/SideMenu/SideMenu.tsx +123 -5
- package/UI/Components/SideMenu/SideMenuItem.tsx +76 -84
- package/UI/Components/SideMenu/SideMenuSection.tsx +55 -23
- package/UI/Components/SideOver/SideOver.tsx +21 -20
- 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/PageScrollLock.ts +79 -3
- package/UI/Utils/PermissionGate.ts +61 -0
- package/UI/Utils/SensitiveUrlToken.ts +112 -0
- package/UI/Utils/Telemetry/BrowserTelemetryConfig.ts +28 -0
- package/UI/Utils/Telemetry/Telemetry.ts +10 -8
- package/UI/Utils/TestLLMProvider.ts +11 -0
- package/Utils/API.ts +129 -3
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +16 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +191 -11
- package/Utils/HTTPResponseBodyReader.ts +221 -0
- package/Utils/Monitor/MonitorMetricType.ts +153 -1
- package/Utils/Monitor/NetworkTopologyUtil.ts +23 -3
- package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +65 -14
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +43 -14
- package/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.ts +247 -0
- package/Utils/NetworkDevice/SnmpCredentialUtil.ts +68 -0
- package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +15 -7
- package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +52 -17
- package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +55 -23
- package/Utils/NetworkDiscovery/DiscoveryScanStatus.ts +77 -0
- package/Utils/NetworkDiscovery/PingMonitorBuilder.ts +115 -13
- package/Utils/NetworkSite/SiteStatusRollupUtil.ts +66 -20
- package/Utils/NetworkSite/TypeHierarchyUtil.ts +313 -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/AnalyticsModels/Span.js +14 -0
- package/build/dist/Models/AnalyticsModels/Span.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/EnterpriseLicense.js +59 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.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/Index.js +10 -0
- package/build/dist/Models/DatabaseModels/Index.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/Monitor.js +75 -0
- package/build/dist/Models/DatabaseModels/Monitor.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/NetworkAlertPolicy.js +713 -0
- package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +180 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSite.js +200 -2
- package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSiteType.js +102 -3
- package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js +878 -0
- package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js.map +1 -0
- 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/TelemetryException.js +123 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.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/UserNotificationEmailRollupBatch.js +363 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +402 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js +296 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserTelegram.js +0 -4
- package/build/dist/Models/DatabaseModels/UserTelegram.js.map +1 -1
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +273 -60
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
- package/build/dist/Server/API/LlmProviderAPI.js +108 -13
- package/build/dist/Server/API/LlmProviderAPI.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 +41 -2
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js +24 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js +111 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js +77 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js +50 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js +83 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js.map +1 -0
- 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 +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +52 -12
- 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/BearerTokenAuthorization.js +12 -0
- package/build/dist/Server/Middleware/BearerTokenAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/ProjectAuthorization.js +11 -0
- package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/SCIMAuthorization.js +12 -0
- package/build/dist/Server/Middleware/SCIMAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +326 -8
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AIBillingService.js +70 -16
- package/build/dist/Server/Services/AIBillingService.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/EnterpriseLicenseInstanceService.js +167 -0
- package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseService.js +39 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
- 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/Index.js +10 -0
- package/build/dist/Server/Services/Index.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 +148 -21
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +127 -8
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +162 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js +1683 -0
- package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js.map +1 -0
- package/build/dist/Server/Services/NetworkAlertPolicyService.js +732 -0
- package/build/dist/Server/Services/NetworkAlertPolicyService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +89 -36
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +54 -11
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +841 -70
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteService.js +1145 -107
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteTypeService.js +863 -0
- package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js +217 -0
- package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js.map +1 -0
- package/build/dist/Server/Services/NotificationService.js +80 -17
- package/build/dist/Server/Services/NotificationService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +88 -30
- 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/StatusPagePrivateUserService.js +92 -2
- package/build/dist/Server/Services/StatusPagePrivateUserService.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/UserNotificationEmailRollupBatchService.js +76 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js +77 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js +111 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationSettingService.js +66 -20
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +90 -0
- package/build/dist/Server/Services/UserService.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 +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +14 -3
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +10 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +10 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +54 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +18 -4
- package/build/dist/Server/Utils/AI/Toolbox/AlertTools.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/Billing/BillingFailureNoticeThrottle.js +59 -0
- package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js.map +1 -0
- 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/DataSource/HttpFetch.js +2 -1
- package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +124 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +733 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +497 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +257 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -0
- package/build/dist/Server/Utils/FrontendEnvironment.js +33 -0
- package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -0
- package/build/dist/Server/Utils/LLM/LLMService.js +64 -1
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/LogRedaction.js +28 -0
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
- package/build/dist/Server/Utils/Logger.js +73 -1
- 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/DatabaseMonitorCriteria.js +141 -0
- package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.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/Criteria/SnmpMonitorCriteria.js +51 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.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/MonitorCriteriaDataExtractor.js +7 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +125 -13
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +158 -6
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.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/MonitorMetricUtil.js +33 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +54 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +330 -21
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +55 -10
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +178 -49
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +119 -29
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.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/NetworkDevice/DeviceHealthAggregation.js +30 -17
- package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js.map +1 -1
- package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js +158 -0
- package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js.map +1 -0
- package/build/dist/Server/Utils/OutboundUserAgent.js +123 -0
- package/build/dist/Server/Utils/OutboundUserAgent.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 +41 -28
- 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/CaptureSpan.js +28 -8
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js +95 -0
- package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.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/SpanUtil.js +29 -0
- package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
- 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/Telemetry.js +162 -46
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- 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/AI/ExceptionAIClassification.js +10 -24
- package/build/dist/Types/AI/ExceptionAIClassification.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/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js +2 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js.map +1 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js +7 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js.map +1 -0
- package/build/dist/Types/Exception/ApiException.js +9 -0
- package/build/dist/Types/Exception/ApiException.js.map +1 -1
- package/build/dist/Types/Exception/BadDataException.js +10 -0
- package/build/dist/Types/Exception/BadDataException.js.map +1 -1
- package/build/dist/Types/Exception/BadRequestException.js +10 -0
- package/build/dist/Types/Exception/BadRequestException.js.map +1 -1
- package/build/dist/Types/Exception/Exception.js +56 -0
- package/build/dist/Types/Exception/Exception.js.map +1 -1
- package/build/dist/Types/Exception/ForbiddenException.js +9 -0
- package/build/dist/Types/Exception/ForbiddenException.js.map +1 -1
- package/build/dist/Types/Exception/NotAuthenticatedException.js +9 -0
- package/build/dist/Types/Exception/NotAuthenticatedException.js.map +1 -1
- package/build/dist/Types/Exception/NotAuthorizedException.js +9 -0
- package/build/dist/Types/Exception/NotAuthorizedException.js.map +1 -1
- package/build/dist/Types/Exception/NotFoundException.js +10 -0
- package/build/dist/Types/Exception/NotFoundException.js.map +1 -1
- package/build/dist/Types/Exception/PayloadTooLargeException.js +10 -0
- package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -1
- package/build/dist/Types/Exception/PaymentRequiredException.js +9 -0
- package/build/dist/Types/Exception/PaymentRequiredException.js.map +1 -1
- package/build/dist/Types/Exception/ServiceUnavailableException.js +9 -0
- package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -1
- package/build/dist/Types/Exception/SsoAuthorizationException.js +9 -0
- package/build/dist/Types/Exception/SsoAuthorizationException.js.map +1 -1
- package/build/dist/Types/Exception/TenantNotFoundException.js +10 -0
- package/build/dist/Types/Exception/TenantNotFoundException.js.map +1 -1
- package/build/dist/Types/Exception/TimeoutException.js +9 -0
- package/build/dist/Types/Exception/TimeoutException.js.map +1 -1
- package/build/dist/Types/Exception/TooManyRequestsException.js +9 -0
- package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -1
- package/build/dist/Types/Exception/UnableToReachServer.js +9 -0
- package/build/dist/Types/Exception/UnableToReachServer.js.map +1 -1
- package/build/dist/Types/Exception/WebsiteRequestException.js +9 -0
- package/build/dist/Types/Exception/WebsiteRequestException.js.map +1 -1
- 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/CriteriaFilter.js +45 -2
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/DatabaseMetricCatalog.js +594 -0
- package/build/dist/Types/Monitor/DatabaseMetricCatalog.js.map +1 -0
- package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js +21 -0
- package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js.map +1 -0
- 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/MonitorCriteriaInstance.js +70 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorMetricType.js +61 -0
- package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +54 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js +122 -0
- package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +45 -1
- package/build/dist/Types/Monitor/MonitorType.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/SnmpMonitor/NetworkDeviceAlertPack.js +21 -1
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
- package/build/dist/Types/Monitor/SqlConnectionConfig.js +2 -0
- package/build/dist/Types/Monitor/SqlConnectionConfig.js.map +1 -0
- package/build/dist/Types/Monitor/UptimeHistoryLabels.js +17 -0
- package/build/dist/Types/Monitor/UptimeHistoryLabels.js.map +1 -0
- package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js +172 -0
- package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js.map +1 -0
- package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +40 -22
- package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -1
- package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js +26 -0
- package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js.map +1 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js +186 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js.map +1 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js +87 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.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/Permission.js +80 -0
- package/build/dist/Types/Permission.js.map +1 -1
- 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/ErrorClass.js +216 -0
- package/build/dist/Types/Telemetry/ErrorClass.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/Telemetry/UnitOfWork.js +59 -0
- package/build/dist/Types/Telemetry/UnitOfWork.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/CommandPalette/CommandPalette.js +2 -7
- package/build/dist/UI/Components/CommandPalette/CommandPalette.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/EditionLabel/EditionLabel.js +3 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- 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/Modal/Modal.js +2 -7
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- 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 +77 -0
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/UI/Components/ProgressBar/ProgressBar.js +12 -1
- package/build/dist/UI/Components/ProgressBar/ProgressBar.js.map +1 -1
- package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +6 -6
- package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js +67 -5
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuItem.js +49 -53
- package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js +25 -7
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
- package/build/dist/UI/Components/SideOver/SideOver.js +5 -20
- package/build/dist/UI/Components/SideOver/SideOver.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/PageScrollLock.js +31 -3
- package/build/dist/UI/Utils/PageScrollLock.js.map +1 -1
- package/build/dist/UI/Utils/PermissionGate.js +42 -1
- package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
- package/build/dist/UI/Utils/SensitiveUrlToken.js +97 -0
- package/build/dist/UI/Utils/SensitiveUrlToken.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/UI/Utils/TestLLMProvider.js +4 -5
- package/build/dist/UI/Utils/TestLLMProvider.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/EnterpriseLicense/EnterpriseLicenseSeats.js +15 -0
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +111 -9
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.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/Monitor/MonitorMetricType.js +109 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +8 -3
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js +27 -7
- package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +7 -5
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js +180 -0
- package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js +12 -0
- package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +15 -5
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +44 -15
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +52 -23
- package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js +69 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js +85 -13
- package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +30 -15
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
- package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js +191 -0
- package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.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 +2 -2
|
@@ -0,0 +1,1849 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Contract under test — the Network Alert Policy engine, the ONE place in the
|
|
3
|
+
* product that creates or deletes a policy-owned Monitor.
|
|
4
|
+
*
|
|
5
|
+
* Monitors are billed and they own incident history, so nearly every case
|
|
6
|
+
* here is a case about NOT doing something. The engine is reached from a
|
|
7
|
+
* dozen directions — a device created, re-sited, re-labelled, archived,
|
|
8
|
+
* switched to monitor-backed, handed a probe; a policy saved, enabled,
|
|
9
|
+
* re-scoped, re-pointed, deleted; a five-minute sweep — and each of them
|
|
10
|
+
* ends in `reconcileDevice`, which computes DESIRED against ACTUAL for one
|
|
11
|
+
* device under that device's own Redis lock. What this file pins is the
|
|
12
|
+
* behaviour that would otherwise fail silently and expensively:
|
|
13
|
+
*
|
|
14
|
+
* - TWO POLICIES ON ONE DEVICE each get their own monitor, and neither
|
|
15
|
+
* pass touches the other's row. Ownership is the PAIR (policy,
|
|
16
|
+
* template), not the device.
|
|
17
|
+
* - A SCOPE THAT SHRINKS deletes only monitors stamped with THAT policy.
|
|
18
|
+
* A hand-made Network Device monitor on the same device, and an
|
|
19
|
+
* auto-import rule's, carry no networkAlertPolicyId and are therefore
|
|
20
|
+
* not even in ACTUAL — the query, not a filter afterwards, is what makes
|
|
21
|
+
* that true.
|
|
22
|
+
* - AN UNOWNED (device, template) MONITOR IS ADOPTED, never duplicated.
|
|
23
|
+
* Monitor's partial unique index on (autoProvisionedNetworkDeviceId,
|
|
24
|
+
* monitorTemplateId) would refuse the duplicate on this pass and on
|
|
25
|
+
* every pass after it, so the policy would report a failure forever
|
|
26
|
+
* beside a perfectly good monitor.
|
|
27
|
+
* - A DEVICE THAT STOPS BEING PROVISIONABLE — archived, monitor-backed, or
|
|
28
|
+
* with no probe — loses every policy monitor. A monitor-backed device's
|
|
29
|
+
* health is a bound monitor's; a Network Device monitor on it is billed
|
|
30
|
+
* for a poll that will never happen.
|
|
31
|
+
* - A DISABLED POLICY PAUSES its monitors instead of deleting them, and
|
|
32
|
+
* enabling reverses it. Deleting would lose the incident history and
|
|
33
|
+
* re-bill the fleet on the way back.
|
|
34
|
+
* - THE PLAN IS ASKED ONCE PER RUN and the run stops at the first refusal,
|
|
35
|
+
* so a project that cannot hold another monitor gets one sentence in
|
|
36
|
+
* lastSyncError rather than five hundred identical failures.
|
|
37
|
+
* - THE LOCK is per device, taken before anything is read, released even
|
|
38
|
+
* when the body throws, and a lock somebody else holds means this pass
|
|
39
|
+
* does nothing at all.
|
|
40
|
+
*
|
|
41
|
+
* The collaborating singleton services — and the Semaphore module, which
|
|
42
|
+
* would otherwise reach Redis — are stubbed at the MODULE level before the
|
|
43
|
+
* engine is imported: their real files reach Postgres through
|
|
44
|
+
* DatabaseService, and nothing here should touch any of it.
|
|
45
|
+
*
|
|
46
|
+
* MonitorService.findBy and NetworkDeviceService.findBy are backed by small
|
|
47
|
+
* in-memory tables rather than by call-order mocks, because the engine asks
|
|
48
|
+
* them several different questions per pass and a `mockResolvedValueOnce`
|
|
49
|
+
* chain would pass for the wrong reason the moment the query order changed.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
jest.mock("../../../Server/EnvironmentConfig", () => {
|
|
53
|
+
return {
|
|
54
|
+
...(jest.requireActual("../../../Server/EnvironmentConfig") as Record<
|
|
55
|
+
string,
|
|
56
|
+
unknown
|
|
57
|
+
>),
|
|
58
|
+
IsBillingEnabled: true,
|
|
59
|
+
AllowedActiveMonitorCountInFreePlan: 10,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
jest.mock("../../../Server/Services/MonitorService", () => {
|
|
64
|
+
return {
|
|
65
|
+
__esModule: true,
|
|
66
|
+
default: {
|
|
67
|
+
create: jest.fn(),
|
|
68
|
+
findBy: jest.fn(),
|
|
69
|
+
findOneBy: jest.fn(),
|
|
70
|
+
countBy: jest.fn(),
|
|
71
|
+
deleteBy: jest.fn(),
|
|
72
|
+
updateBy: jest.fn(),
|
|
73
|
+
updateColumnsByIdWithoutHooks: jest.fn(),
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
jest.mock("../../../Server/Services/MonitorTemplateService", () => {
|
|
79
|
+
return {
|
|
80
|
+
__esModule: true,
|
|
81
|
+
default: {
|
|
82
|
+
findOneBy: jest.fn(),
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
jest.mock("../../../Server/Services/NetworkAlertPolicyService", () => {
|
|
88
|
+
return {
|
|
89
|
+
__esModule: true,
|
|
90
|
+
default: {
|
|
91
|
+
findBy: jest.fn(),
|
|
92
|
+
findOneBy: jest.fn(),
|
|
93
|
+
updateColumnsByIdWithoutHooks: jest.fn(),
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
jest.mock("../../../Server/Services/NetworkDeviceService", () => {
|
|
99
|
+
return {
|
|
100
|
+
__esModule: true,
|
|
101
|
+
default: {
|
|
102
|
+
findBy: jest.fn(),
|
|
103
|
+
findOneBy: jest.fn(),
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
jest.mock("../../../Server/Services/ProjectService", () => {
|
|
109
|
+
return {
|
|
110
|
+
__esModule: true,
|
|
111
|
+
default: {
|
|
112
|
+
getCurrentPlan: jest.fn(),
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
jest.mock("../../../Server/Infrastructure/Semaphore", () => {
|
|
118
|
+
return {
|
|
119
|
+
__esModule: true,
|
|
120
|
+
default: {
|
|
121
|
+
lock: jest.fn(),
|
|
122
|
+
release: jest.fn(),
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
jest.mock("../../../Server/Utils/Logger", () => {
|
|
128
|
+
return {
|
|
129
|
+
__esModule: true,
|
|
130
|
+
default: {
|
|
131
|
+
debug: jest.fn(),
|
|
132
|
+
info: jest.fn(),
|
|
133
|
+
warn: jest.fn(),
|
|
134
|
+
error: jest.fn(),
|
|
135
|
+
trace: jest.fn(),
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
import NetworkAlertPolicyEngineService, {
|
|
141
|
+
MAX_MONITORS_PER_POLICY_SYNC,
|
|
142
|
+
POLICY_DEVICE_LOCK_NAMESPACE,
|
|
143
|
+
PolicyRunContext,
|
|
144
|
+
policyDeviceLockKey,
|
|
145
|
+
} from "../../../Server/Services/NetworkAlertPolicyEngineService";
|
|
146
|
+
import MonitorService from "../../../Server/Services/MonitorService";
|
|
147
|
+
import MonitorTemplateService from "../../../Server/Services/MonitorTemplateService";
|
|
148
|
+
import NetworkAlertPolicyService from "../../../Server/Services/NetworkAlertPolicyService";
|
|
149
|
+
import NetworkDeviceService from "../../../Server/Services/NetworkDeviceService";
|
|
150
|
+
import ProjectService from "../../../Server/Services/ProjectService";
|
|
151
|
+
import Semaphore from "../../../Server/Infrastructure/Semaphore";
|
|
152
|
+
import Label from "../../../Models/DatabaseModels/Label";
|
|
153
|
+
import Monitor from "../../../Models/DatabaseModels/Monitor";
|
|
154
|
+
import MonitorTemplate from "../../../Models/DatabaseModels/MonitorTemplate";
|
|
155
|
+
import NetworkAlertPolicy from "../../../Models/DatabaseModels/NetworkAlertPolicy";
|
|
156
|
+
import NetworkDevice from "../../../Models/DatabaseModels/NetworkDevice";
|
|
157
|
+
import FindBy from "../../../Server/Types/Database/FindBy";
|
|
158
|
+
import FindOneBy from "../../../Server/Types/Database/FindOneBy";
|
|
159
|
+
import { PlanType } from "../../../Types/Billing/SubscriptionPlan";
|
|
160
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
161
|
+
import MonitorStep from "../../../Types/Monitor/MonitorStep";
|
|
162
|
+
import MonitorSteps from "../../../Types/Monitor/MonitorSteps";
|
|
163
|
+
import MonitorType from "../../../Types/Monitor/MonitorType";
|
|
164
|
+
import NetworkDeviceMonitoringMethod from "../../../Types/NetworkDevice/NetworkDeviceMonitoringMethod";
|
|
165
|
+
import NetworkAlertPolicyScope from "../../../Types/NetworkDevice/NetworkAlertPolicyScope";
|
|
166
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
167
|
+
import PositiveNumber from "../../../Types/PositiveNumber";
|
|
168
|
+
import { beforeEach, describe, expect, it, jest } from "@jest/globals";
|
|
169
|
+
|
|
170
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
171
|
+
"11111111-1111-4111-8111-111111111111",
|
|
172
|
+
);
|
|
173
|
+
const DEVICE_ID: ObjectID = new ObjectID(
|
|
174
|
+
"22222222-2222-4222-8222-222222222222",
|
|
175
|
+
);
|
|
176
|
+
const OTHER_DEVICE_ID: ObjectID = new ObjectID(
|
|
177
|
+
"2b2b2b2b-2b2b-4b2b-8b2b-2b2b2b2b2b2b",
|
|
178
|
+
);
|
|
179
|
+
const POLICY_ID: ObjectID = new ObjectID(
|
|
180
|
+
"33333333-3333-4333-8333-333333333333",
|
|
181
|
+
);
|
|
182
|
+
const OTHER_POLICY_ID: ObjectID = new ObjectID(
|
|
183
|
+
"3b3b3b3b-3b3b-4b3b-8b3b-3b3b3b3b3b3b",
|
|
184
|
+
);
|
|
185
|
+
const TEMPLATE_ID: ObjectID = new ObjectID(
|
|
186
|
+
"44444444-4444-4444-8444-444444444444",
|
|
187
|
+
);
|
|
188
|
+
const OTHER_TEMPLATE_ID: ObjectID = new ObjectID(
|
|
189
|
+
"4b4b4b4b-4b4b-4b4b-8b4b-4b4b4b4b4b4b",
|
|
190
|
+
);
|
|
191
|
+
const PROBE_ID: ObjectID = new ObjectID("55555555-5555-4555-8555-555555555555");
|
|
192
|
+
const SITE_ID: ObjectID = new ObjectID("66666666-6666-4666-8666-666666666666");
|
|
193
|
+
const OTHER_SITE_ID: ObjectID = new ObjectID(
|
|
194
|
+
"6b6b6b6b-6b6b-4b6b-8b6b-6b6b6b6b6b6b",
|
|
195
|
+
);
|
|
196
|
+
const LABEL_ID: ObjectID = new ObjectID("77777777-7777-4777-8777-777777777777");
|
|
197
|
+
|
|
198
|
+
// What the mocked Semaphore.lock hands back and release must get back.
|
|
199
|
+
const FAKE_MUTEX: { id: string } = { id: "fake-device-mutex" };
|
|
200
|
+
|
|
201
|
+
const monitorCreateMock: jest.Mock =
|
|
202
|
+
MonitorService.create as unknown as jest.Mock;
|
|
203
|
+
const monitorFindByMock: jest.Mock =
|
|
204
|
+
MonitorService.findBy as unknown as jest.Mock;
|
|
205
|
+
const monitorFindOneByMock: jest.Mock =
|
|
206
|
+
MonitorService.findOneBy as unknown as jest.Mock;
|
|
207
|
+
const monitorCountByMock: jest.Mock =
|
|
208
|
+
MonitorService.countBy as unknown as jest.Mock;
|
|
209
|
+
const monitorDeleteByMock: jest.Mock =
|
|
210
|
+
MonitorService.deleteBy as unknown as jest.Mock;
|
|
211
|
+
const monitorUpdateByMock: jest.Mock =
|
|
212
|
+
MonitorService.updateBy as unknown as jest.Mock;
|
|
213
|
+
const monitorStampMock: jest.Mock =
|
|
214
|
+
MonitorService.updateColumnsByIdWithoutHooks as unknown as jest.Mock;
|
|
215
|
+
const templateFindOneByMock: jest.Mock =
|
|
216
|
+
MonitorTemplateService.findOneBy as unknown as jest.Mock;
|
|
217
|
+
const policyFindByMock: jest.Mock =
|
|
218
|
+
NetworkAlertPolicyService.findBy as unknown as jest.Mock;
|
|
219
|
+
const policyFindOneByMock: jest.Mock =
|
|
220
|
+
NetworkAlertPolicyService.findOneBy as unknown as jest.Mock;
|
|
221
|
+
const policyStampMock: jest.Mock =
|
|
222
|
+
NetworkAlertPolicyService.updateColumnsByIdWithoutHooks as unknown as jest.Mock;
|
|
223
|
+
const deviceFindByMock: jest.Mock =
|
|
224
|
+
NetworkDeviceService.findBy as unknown as jest.Mock;
|
|
225
|
+
const deviceFindOneByMock: jest.Mock =
|
|
226
|
+
NetworkDeviceService.findOneBy as unknown as jest.Mock;
|
|
227
|
+
const currentPlanMock: jest.Mock =
|
|
228
|
+
ProjectService.getCurrentPlan as unknown as jest.Mock;
|
|
229
|
+
const semaphoreLockMock: jest.Mock = Semaphore.lock as unknown as jest.Mock;
|
|
230
|
+
const semaphoreReleaseMock: jest.Mock =
|
|
231
|
+
Semaphore.release as unknown as jest.Mock;
|
|
232
|
+
|
|
233
|
+
/*
|
|
234
|
+
* A query value the engine could have written. Understanding the raw
|
|
235
|
+
* operators (rather than only exact values) is what lets the fake tables
|
|
236
|
+
* answer the SAME questions the database would — including the two that
|
|
237
|
+
* carry the whole safety story here, `networkAlertPolicyId IS NOT NULL` and
|
|
238
|
+
* `IS NULL`.
|
|
239
|
+
*/
|
|
240
|
+
function matchesQueryValue(actual: unknown, expected: unknown): boolean {
|
|
241
|
+
const findOperator: {
|
|
242
|
+
getSql?: (alias: string) => string;
|
|
243
|
+
objectLiteralParameters?: Record<string, unknown>;
|
|
244
|
+
} = expected as {
|
|
245
|
+
getSql?: (alias: string) => string;
|
|
246
|
+
objectLiteralParameters?: Record<string, unknown>;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
if (findOperator && typeof findOperator.getSql === "function") {
|
|
250
|
+
const sql: string = findOperator.getSql("column");
|
|
251
|
+
const parameters: Array<unknown> = Object.values(
|
|
252
|
+
findOperator.objectLiteralParameters || {},
|
|
253
|
+
).flat();
|
|
254
|
+
|
|
255
|
+
if (sql.includes("IS NOT NULL")) {
|
|
256
|
+
return actual !== null && actual !== undefined;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (sql.includes("IS NULL")) {
|
|
260
|
+
return actual === null || actual === undefined;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (sql.includes("IN (")) {
|
|
264
|
+
return parameters.some((parameter: unknown): boolean => {
|
|
265
|
+
return parameter?.toString() === actual?.toString();
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (sql.includes(">")) {
|
|
270
|
+
return (
|
|
271
|
+
actual !== null &&
|
|
272
|
+
actual !== undefined &&
|
|
273
|
+
String(actual) > String(parameters[0])
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
throw new Error(`Unhandled query operator in test matcher: ${sql}`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (expected === null || expected === undefined) {
|
|
281
|
+
return actual === null || actual === undefined;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (typeof expected === "boolean") {
|
|
285
|
+
return Boolean(actual) === expected;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return actual?.toString() === expected.toString();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function matchesQuery(
|
|
292
|
+
row: Record<string, unknown>,
|
|
293
|
+
query: Record<string, unknown>,
|
|
294
|
+
): boolean {
|
|
295
|
+
for (const [column, expected] of Object.entries(query)) {
|
|
296
|
+
if (column === "labels") {
|
|
297
|
+
/*
|
|
298
|
+
* The many-to-many spelling: `labels: [id, id]` is "carries any of
|
|
299
|
+
* these labels", which is exactly what the scope means by a label list.
|
|
300
|
+
*/
|
|
301
|
+
const wanted: Array<unknown> = expected as Array<unknown>;
|
|
302
|
+
const carried: Array<Label> = (row["labels"] as Array<Label>) || [];
|
|
303
|
+
|
|
304
|
+
const hasAny: boolean = carried.some((label: Label): boolean => {
|
|
305
|
+
return wanted.some((id: unknown): boolean => {
|
|
306
|
+
return id?.toString() === label.id?.toString();
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
if (!hasAny) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const actual: unknown = column === "_id" ? row["_id"] : row[column];
|
|
318
|
+
|
|
319
|
+
if (!matchesQueryValue(actual, expected)) {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// The fake tables. Rebuilt per test.
|
|
328
|
+
let monitorTable: Array<Monitor> = [];
|
|
329
|
+
let deviceTable: Array<NetworkDevice> = [];
|
|
330
|
+
let policyTable: Array<NetworkAlertPolicy> = [];
|
|
331
|
+
|
|
332
|
+
function sortAndPage<TRow extends { _id?: string }>(
|
|
333
|
+
rows: Array<TRow>,
|
|
334
|
+
findBy: FindBy<never>,
|
|
335
|
+
): Array<TRow> {
|
|
336
|
+
const sorted: Array<TRow> = [...rows].sort(
|
|
337
|
+
(left: TRow, right: TRow): number => {
|
|
338
|
+
return (left._id || "").localeCompare(right._id || "");
|
|
339
|
+
},
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
const limit: number =
|
|
343
|
+
typeof findBy.limit === "number" ? findBy.limit : sorted.length;
|
|
344
|
+
|
|
345
|
+
return sorted.slice(0, limit);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function installFakeTables(): void {
|
|
349
|
+
monitorFindByMock.mockImplementation(
|
|
350
|
+
async (findBy: FindBy<Monitor>): Promise<Array<Monitor>> => {
|
|
351
|
+
return sortAndPage(
|
|
352
|
+
monitorTable.filter((monitor: Monitor): boolean => {
|
|
353
|
+
return matchesQuery(
|
|
354
|
+
monitor as unknown as Record<string, unknown>,
|
|
355
|
+
findBy.query as Record<string, unknown>,
|
|
356
|
+
);
|
|
357
|
+
}),
|
|
358
|
+
findBy as unknown as FindBy<never>,
|
|
359
|
+
);
|
|
360
|
+
},
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
monitorFindOneByMock.mockImplementation(
|
|
364
|
+
async (findOneBy: FindOneBy<Monitor>): Promise<Monitor | null> => {
|
|
365
|
+
return (
|
|
366
|
+
monitorTable.find((monitor: Monitor): boolean => {
|
|
367
|
+
return matchesQuery(
|
|
368
|
+
monitor as unknown as Record<string, unknown>,
|
|
369
|
+
findOneBy.query as Record<string, unknown>,
|
|
370
|
+
);
|
|
371
|
+
}) || null
|
|
372
|
+
);
|
|
373
|
+
},
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
deviceFindByMock.mockImplementation(
|
|
377
|
+
async (findBy: FindBy<NetworkDevice>): Promise<Array<NetworkDevice>> => {
|
|
378
|
+
return sortAndPage(
|
|
379
|
+
deviceTable.filter((device: NetworkDevice): boolean => {
|
|
380
|
+
return matchesQuery(
|
|
381
|
+
device as unknown as Record<string, unknown>,
|
|
382
|
+
findBy.query as Record<string, unknown>,
|
|
383
|
+
);
|
|
384
|
+
}),
|
|
385
|
+
findBy as unknown as FindBy<never>,
|
|
386
|
+
);
|
|
387
|
+
},
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
deviceFindOneByMock.mockImplementation(
|
|
391
|
+
async (
|
|
392
|
+
findOneBy: FindOneBy<NetworkDevice>,
|
|
393
|
+
): Promise<NetworkDevice | null> => {
|
|
394
|
+
return (
|
|
395
|
+
deviceTable.find((device: NetworkDevice): boolean => {
|
|
396
|
+
return matchesQuery(
|
|
397
|
+
device as unknown as Record<string, unknown>,
|
|
398
|
+
findOneBy.query as Record<string, unknown>,
|
|
399
|
+
);
|
|
400
|
+
}) || null
|
|
401
|
+
);
|
|
402
|
+
},
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
policyFindByMock.mockImplementation(
|
|
406
|
+
async (
|
|
407
|
+
findBy: FindBy<NetworkAlertPolicy>,
|
|
408
|
+
): Promise<Array<NetworkAlertPolicy>> => {
|
|
409
|
+
return policyTable.filter((policy: NetworkAlertPolicy): boolean => {
|
|
410
|
+
return matchesQuery(
|
|
411
|
+
policy as unknown as Record<string, unknown>,
|
|
412
|
+
findBy.query as Record<string, unknown>,
|
|
413
|
+
);
|
|
414
|
+
});
|
|
415
|
+
},
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
policyFindOneByMock.mockImplementation(
|
|
419
|
+
async (
|
|
420
|
+
findOneBy: FindOneBy<NetworkAlertPolicy>,
|
|
421
|
+
): Promise<NetworkAlertPolicy | null> => {
|
|
422
|
+
return (
|
|
423
|
+
policyTable.find((policy: NetworkAlertPolicy): boolean => {
|
|
424
|
+
return matchesQuery(
|
|
425
|
+
policy as unknown as Record<string, unknown>,
|
|
426
|
+
findOneBy.query as Record<string, unknown>,
|
|
427
|
+
);
|
|
428
|
+
}) || null
|
|
429
|
+
);
|
|
430
|
+
},
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
/*
|
|
434
|
+
* Writes land back in the fake tables so a second pass in the same test
|
|
435
|
+
* sees what the first one did — which is the only way to assert that
|
|
436
|
+
* reconciliation is idempotent.
|
|
437
|
+
*/
|
|
438
|
+
monitorCreateMock.mockImplementation(
|
|
439
|
+
async (createBy: { data: Monitor }): Promise<Monitor> => {
|
|
440
|
+
const monitor: Monitor = createBy.data;
|
|
441
|
+
monitor.id = ObjectID.generate();
|
|
442
|
+
monitorTable.push(monitor);
|
|
443
|
+
|
|
444
|
+
return monitor;
|
|
445
|
+
},
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
monitorDeleteByMock.mockImplementation(
|
|
449
|
+
async (deleteBy: { query: Record<string, unknown> }): Promise<number> => {
|
|
450
|
+
const remaining: Array<Monitor> = monitorTable.filter(
|
|
451
|
+
(monitor: Monitor): boolean => {
|
|
452
|
+
return !matchesQuery(
|
|
453
|
+
monitor as unknown as Record<string, unknown>,
|
|
454
|
+
deleteBy.query,
|
|
455
|
+
);
|
|
456
|
+
},
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
const deleted: number = monitorTable.length - remaining.length;
|
|
460
|
+
monitorTable = remaining;
|
|
461
|
+
|
|
462
|
+
return deleted;
|
|
463
|
+
},
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
monitorUpdateByMock.mockImplementation(
|
|
467
|
+
async (updateBy: {
|
|
468
|
+
query: Record<string, unknown>;
|
|
469
|
+
data: Record<string, unknown>;
|
|
470
|
+
}): Promise<number> => {
|
|
471
|
+
let updated: number = 0;
|
|
472
|
+
|
|
473
|
+
for (const monitor of monitorTable) {
|
|
474
|
+
if (
|
|
475
|
+
matchesQuery(
|
|
476
|
+
monitor as unknown as Record<string, unknown>,
|
|
477
|
+
updateBy.query,
|
|
478
|
+
)
|
|
479
|
+
) {
|
|
480
|
+
Object.assign(monitor, updateBy.data);
|
|
481
|
+
updated++;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return updated;
|
|
486
|
+
},
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
monitorStampMock.mockImplementation(
|
|
490
|
+
async (input: {
|
|
491
|
+
id: ObjectID;
|
|
492
|
+
data: Record<string, unknown>;
|
|
493
|
+
}): Promise<void> => {
|
|
494
|
+
const monitor: Monitor | undefined = monitorTable.find(
|
|
495
|
+
(candidate: Monitor): boolean => {
|
|
496
|
+
return candidate.id?.toString() === input.id.toString();
|
|
497
|
+
},
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
if (monitor) {
|
|
501
|
+
Object.assign(monitor, input.data);
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
);
|
|
505
|
+
|
|
506
|
+
policyStampMock.mockResolvedValue(undefined);
|
|
507
|
+
templateFindOneByMock.mockImplementation(
|
|
508
|
+
async (
|
|
509
|
+
findOneBy: FindOneBy<MonitorTemplate>,
|
|
510
|
+
): Promise<MonitorTemplate | null> => {
|
|
511
|
+
const queriedId: unknown = (findOneBy.query as Record<string, unknown>)[
|
|
512
|
+
"_id"
|
|
513
|
+
];
|
|
514
|
+
|
|
515
|
+
return queriedId?.toString() === TEMPLATE_ID.toString()
|
|
516
|
+
? monitorTemplate(TEMPLATE_ID, "Reachability")
|
|
517
|
+
: queriedId?.toString() === OTHER_TEMPLATE_ID.toString()
|
|
518
|
+
? monitorTemplate(OTHER_TEMPLATE_ID, "Interfaces")
|
|
519
|
+
: null;
|
|
520
|
+
},
|
|
521
|
+
);
|
|
522
|
+
|
|
523
|
+
semaphoreLockMock.mockResolvedValue(FAKE_MUTEX);
|
|
524
|
+
semaphoreReleaseMock.mockResolvedValue(undefined);
|
|
525
|
+
currentPlanMock.mockResolvedValue({
|
|
526
|
+
plan: PlanType.Growth,
|
|
527
|
+
isSubscriptionUnpaid: false,
|
|
528
|
+
});
|
|
529
|
+
monitorCountByMock.mockResolvedValue(new PositiveNumber(0));
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function monitorTemplate(id: ObjectID, name: string): MonitorTemplate {
|
|
533
|
+
const template: MonitorTemplate = new MonitorTemplate();
|
|
534
|
+
template.id = id;
|
|
535
|
+
template.projectId = PROJECT_ID;
|
|
536
|
+
template.monitorType = MonitorType.NetworkDevice;
|
|
537
|
+
template.monitorName = name;
|
|
538
|
+
|
|
539
|
+
const step: MonitorStep = new MonitorStep();
|
|
540
|
+
step.data!.networkDeviceMonitor = {
|
|
541
|
+
// A design-time placeholder; buildMonitor rebinds it to the real device.
|
|
542
|
+
networkDeviceId: ObjectID.generate().toString(),
|
|
543
|
+
monitorInterfaces: false,
|
|
544
|
+
oids: [],
|
|
545
|
+
};
|
|
546
|
+
template.monitorSteps = new MonitorSteps();
|
|
547
|
+
template.monitorSteps.data = { monitorStepsInstanceArray: [step] };
|
|
548
|
+
|
|
549
|
+
return template;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function device(
|
|
553
|
+
overrides: Partial<NetworkDevice> = {},
|
|
554
|
+
id: ObjectID = DEVICE_ID,
|
|
555
|
+
): NetworkDevice {
|
|
556
|
+
const networkDevice: NetworkDevice = new NetworkDevice();
|
|
557
|
+
networkDevice.id = id;
|
|
558
|
+
networkDevice.projectId = PROJECT_ID;
|
|
559
|
+
networkDevice.name = "Core switch";
|
|
560
|
+
networkDevice.isArchived = false;
|
|
561
|
+
networkDevice.monitoringMethod = NetworkDeviceMonitoringMethod.Probe;
|
|
562
|
+
networkDevice.probeId = PROBE_ID;
|
|
563
|
+
networkDevice.siteId = SITE_ID;
|
|
564
|
+
Object.assign(networkDevice, overrides);
|
|
565
|
+
|
|
566
|
+
return networkDevice;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function policy(
|
|
570
|
+
overrides: Partial<NetworkAlertPolicy> = {},
|
|
571
|
+
id: ObjectID = POLICY_ID,
|
|
572
|
+
): NetworkAlertPolicy {
|
|
573
|
+
const alertPolicy: NetworkAlertPolicy = new NetworkAlertPolicy();
|
|
574
|
+
alertPolicy.id = id;
|
|
575
|
+
alertPolicy.projectId = PROJECT_ID;
|
|
576
|
+
alertPolicy.name = "Warehouse switches";
|
|
577
|
+
alertPolicy.isEnabled = true;
|
|
578
|
+
alertPolicy.monitorTemplateId = TEMPLATE_ID;
|
|
579
|
+
alertPolicy.scope = {} as NetworkAlertPolicyScope;
|
|
580
|
+
Object.assign(alertPolicy, overrides);
|
|
581
|
+
|
|
582
|
+
return alertPolicy;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function monitorRow(overrides: Partial<Monitor> = {}): Monitor {
|
|
586
|
+
const monitor: Monitor = new Monitor();
|
|
587
|
+
monitor.id = ObjectID.generate();
|
|
588
|
+
monitor.projectId = PROJECT_ID;
|
|
589
|
+
monitor.monitorType = MonitorType.NetworkDevice;
|
|
590
|
+
monitor.disableActiveMonitoring = false;
|
|
591
|
+
Object.assign(monitor, overrides);
|
|
592
|
+
|
|
593
|
+
return monitor;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function labelled(labelId: ObjectID): Array<Label> {
|
|
597
|
+
const label: Label = new Label();
|
|
598
|
+
label.id = labelId;
|
|
599
|
+
|
|
600
|
+
return [label];
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function monitorsOfDevice(deviceId: ObjectID = DEVICE_ID): Array<Monitor> {
|
|
604
|
+
return monitorTable.filter((monitor: Monitor): boolean => {
|
|
605
|
+
return (
|
|
606
|
+
monitor.autoProvisionedNetworkDeviceId?.toString() === deviceId.toString()
|
|
607
|
+
);
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
beforeEach(() => {
|
|
612
|
+
jest.clearAllMocks();
|
|
613
|
+
monitorTable = [];
|
|
614
|
+
deviceTable = [];
|
|
615
|
+
policyTable = [];
|
|
616
|
+
installFakeTables();
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
describe("reconcileDevice provisions what the policies ask for", () => {
|
|
620
|
+
it("creates one monitor for a device an enabled policy covers", async () => {
|
|
621
|
+
deviceTable = [device()];
|
|
622
|
+
policyTable = [policy()];
|
|
623
|
+
|
|
624
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
625
|
+
projectId: PROJECT_ID,
|
|
626
|
+
deviceId: DEVICE_ID,
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
expect(monitorsOfDevice()).toHaveLength(1);
|
|
630
|
+
expect(monitorsOfDevice()[0]!.networkAlertPolicyId?.toString()).toBe(
|
|
631
|
+
POLICY_ID.toString(),
|
|
632
|
+
);
|
|
633
|
+
expect(monitorsOfDevice()[0]!.monitorTemplateId?.toString()).toBe(
|
|
634
|
+
TEMPLATE_ID.toString(),
|
|
635
|
+
);
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
/*
|
|
639
|
+
* The stamp goes on the CREATE, not in a follow-up update. A monitor that
|
|
640
|
+
* exists for a moment without its owner is one a concurrent pass of a
|
|
641
|
+
* different policy could adopt.
|
|
642
|
+
*/
|
|
643
|
+
it("stamps the owning policy in the same write that creates the monitor", async () => {
|
|
644
|
+
deviceTable = [device()];
|
|
645
|
+
policyTable = [policy()];
|
|
646
|
+
|
|
647
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
648
|
+
projectId: PROJECT_ID,
|
|
649
|
+
deviceId: DEVICE_ID,
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
const created: { data: Monitor } = monitorCreateMock.mock.calls[0]![0] as {
|
|
653
|
+
data: Monitor;
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
expect(created.data.networkAlertPolicyId?.toString()).toBe(
|
|
657
|
+
POLICY_ID.toString(),
|
|
658
|
+
);
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
it("is idempotent: a second pass over an already-covered device writes nothing", async () => {
|
|
662
|
+
deviceTable = [device()];
|
|
663
|
+
policyTable = [policy()];
|
|
664
|
+
|
|
665
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
666
|
+
projectId: PROJECT_ID,
|
|
667
|
+
deviceId: DEVICE_ID,
|
|
668
|
+
});
|
|
669
|
+
monitorCreateMock.mockClear();
|
|
670
|
+
monitorDeleteByMock.mockClear();
|
|
671
|
+
|
|
672
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
673
|
+
projectId: PROJECT_ID,
|
|
674
|
+
deviceId: DEVICE_ID,
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
expect(monitorCreateMock).not.toHaveBeenCalled();
|
|
678
|
+
expect(monitorDeleteByMock).not.toHaveBeenCalled();
|
|
679
|
+
expect(monitorsOfDevice()).toHaveLength(1);
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
it("provisions nothing for a device outside every policy's scope", async () => {
|
|
683
|
+
deviceTable = [device({ siteId: OTHER_SITE_ID })];
|
|
684
|
+
policyTable = [policy({ scope: { siteIds: [SITE_ID.toString()] } })];
|
|
685
|
+
|
|
686
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
687
|
+
projectId: PROJECT_ID,
|
|
688
|
+
deviceId: DEVICE_ID,
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
expect(monitorCreateMock).not.toHaveBeenCalled();
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
it("matches a device by label as well as by site", async () => {
|
|
695
|
+
deviceTable = [device({ labels: labelled(LABEL_ID) })];
|
|
696
|
+
policyTable = [policy({ scope: { labelIds: [LABEL_ID.toString()] } })];
|
|
697
|
+
|
|
698
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
699
|
+
projectId: PROJECT_ID,
|
|
700
|
+
deviceId: DEVICE_ID,
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
expect(monitorsOfDevice()).toHaveLength(1);
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
/*
|
|
708
|
+
* THE DANGEROUS CASE. Two policies covering one device is the ordinary
|
|
709
|
+
* situation ("everything gets reachability" plus "warehouse switches get
|
|
710
|
+
* interface alerts"), and it is the one where a wrong ownership key destroys
|
|
711
|
+
* a monitor: if the engine keyed on the DEVICE rather than on (policy,
|
|
712
|
+
* template), each pass would see a monitor that is "not mine" and delete it,
|
|
713
|
+
* and the two policies would take turns removing each other's alerting.
|
|
714
|
+
*/
|
|
715
|
+
describe("two policies on one device", () => {
|
|
716
|
+
beforeEach(() => {
|
|
717
|
+
deviceTable = [device()];
|
|
718
|
+
policyTable = [
|
|
719
|
+
policy(),
|
|
720
|
+
policy(
|
|
721
|
+
{
|
|
722
|
+
name: "Interface alerts",
|
|
723
|
+
monitorTemplateId: OTHER_TEMPLATE_ID,
|
|
724
|
+
},
|
|
725
|
+
OTHER_POLICY_ID,
|
|
726
|
+
),
|
|
727
|
+
];
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
it("gives the device one monitor per policy", async () => {
|
|
731
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
732
|
+
projectId: PROJECT_ID,
|
|
733
|
+
deviceId: DEVICE_ID,
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
const owners: Array<string> = monitorsOfDevice().map(
|
|
737
|
+
(monitor: Monitor): string => {
|
|
738
|
+
return monitor.networkAlertPolicyId!.toString();
|
|
739
|
+
},
|
|
740
|
+
);
|
|
741
|
+
|
|
742
|
+
expect(owners.sort()).toEqual(
|
|
743
|
+
[POLICY_ID.toString(), OTHER_POLICY_ID.toString()].sort(),
|
|
744
|
+
);
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
it("leaves the other policy's monitor alone when one policy's scope stops matching", async () => {
|
|
748
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
749
|
+
projectId: PROJECT_ID,
|
|
750
|
+
deviceId: DEVICE_ID,
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
// The first policy narrows to a site this device is not in.
|
|
754
|
+
policyTable[0]!.scope = {
|
|
755
|
+
siteIds: [OTHER_SITE_ID.toString()],
|
|
756
|
+
} as NetworkAlertPolicyScope;
|
|
757
|
+
|
|
758
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
759
|
+
projectId: PROJECT_ID,
|
|
760
|
+
deviceId: DEVICE_ID,
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
const survivors: Array<Monitor> = monitorsOfDevice();
|
|
764
|
+
|
|
765
|
+
expect(survivors).toHaveLength(1);
|
|
766
|
+
expect(survivors[0]!.networkAlertPolicyId?.toString()).toBe(
|
|
767
|
+
OTHER_POLICY_ID.toString(),
|
|
768
|
+
);
|
|
769
|
+
});
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
/*
|
|
773
|
+
* THE OTHER DANGEROUS CASE. A shrinking scope is the ordinary way a policy
|
|
774
|
+
* stops covering a device, and it is the moment the engine deletes. What it
|
|
775
|
+
* must delete is exactly the rows stamped with the policy that shrank —
|
|
776
|
+
* never the monitor a person built by hand, and never the one an auto-import
|
|
777
|
+
* rule provisioned, both of which sit on the same device and carry the same
|
|
778
|
+
* `autoProvisionedNetworkDeviceId`.
|
|
779
|
+
*/
|
|
780
|
+
describe("a scope that shrinks", () => {
|
|
781
|
+
it("deletes only the monitors the shrinking policy owns", async () => {
|
|
782
|
+
const handMade: Monitor = monitorRow({
|
|
783
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
784
|
+
// No networkAlertPolicyId: nobody's policy made this.
|
|
785
|
+
monitorTemplateId: OTHER_TEMPLATE_ID,
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
monitorTable = [handMade];
|
|
789
|
+
deviceTable = [device()];
|
|
790
|
+
policyTable = [policy()];
|
|
791
|
+
|
|
792
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
793
|
+
projectId: PROJECT_ID,
|
|
794
|
+
deviceId: DEVICE_ID,
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
expect(monitorsOfDevice()).toHaveLength(2);
|
|
798
|
+
|
|
799
|
+
policyTable[0]!.scope = {
|
|
800
|
+
siteIds: [OTHER_SITE_ID.toString()],
|
|
801
|
+
} as NetworkAlertPolicyScope;
|
|
802
|
+
|
|
803
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
804
|
+
projectId: PROJECT_ID,
|
|
805
|
+
deviceId: DEVICE_ID,
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
const survivors: Array<Monitor> = monitorsOfDevice();
|
|
809
|
+
|
|
810
|
+
expect(survivors).toHaveLength(1);
|
|
811
|
+
expect(survivors[0]!.id?.toString()).toBe(handMade.id?.toString());
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
/*
|
|
815
|
+
* ...and the hand-made monitor is not merely filtered out afterwards: the
|
|
816
|
+
* QUERY that reads ACTUAL asks for `networkAlertPolicyId IS NOT NULL`, so
|
|
817
|
+
* a monitor with no owner is never even a candidate for deletion.
|
|
818
|
+
*/
|
|
819
|
+
it("never reads an unowned monitor into the set it may delete", async () => {
|
|
820
|
+
deviceTable = [device()];
|
|
821
|
+
policyTable = [policy()];
|
|
822
|
+
|
|
823
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
824
|
+
projectId: PROJECT_ID,
|
|
825
|
+
deviceId: DEVICE_ID,
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
const actualQuery: Record<string, unknown> = (
|
|
829
|
+
monitorFindByMock.mock.calls[0]![0] as {
|
|
830
|
+
query: Record<string, unknown>;
|
|
831
|
+
}
|
|
832
|
+
).query;
|
|
833
|
+
|
|
834
|
+
expect(
|
|
835
|
+
(
|
|
836
|
+
actualQuery["networkAlertPolicyId"] as {
|
|
837
|
+
getSql: (alias: string) => string;
|
|
838
|
+
}
|
|
839
|
+
).getSql("column"),
|
|
840
|
+
).toContain("IS NOT NULL");
|
|
841
|
+
expect(actualQuery["autoProvisionedNetworkDeviceId"]?.toString()).toBe(
|
|
842
|
+
DEVICE_ID.toString(),
|
|
843
|
+
);
|
|
844
|
+
});
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
/*
|
|
848
|
+
* Adoption. A (device, template) monitor that already exists without an owner
|
|
849
|
+
* occupies the pair Monitor's partial unique index protects, so creating a
|
|
850
|
+
* second one is impossible — not slow, impossible, on this pass and on every
|
|
851
|
+
* pass after it.
|
|
852
|
+
*/
|
|
853
|
+
describe("an unowned monitor for the same (device, template)", () => {
|
|
854
|
+
it("is adopted by stamping the policy, not duplicated", async () => {
|
|
855
|
+
const unowned: Monitor = monitorRow({
|
|
856
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
857
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
monitorTable = [unowned];
|
|
861
|
+
deviceTable = [device()];
|
|
862
|
+
policyTable = [policy()];
|
|
863
|
+
|
|
864
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
865
|
+
projectId: PROJECT_ID,
|
|
866
|
+
deviceId: DEVICE_ID,
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
expect(monitorCreateMock).not.toHaveBeenCalled();
|
|
870
|
+
expect(monitorsOfDevice()).toHaveLength(1);
|
|
871
|
+
expect(unowned.networkAlertPolicyId?.toString()).toBe(POLICY_ID.toString());
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
/*
|
|
875
|
+
* The stamp is a provenance marker, not an operational change: no hooks,
|
|
876
|
+
* no workflow, no realtime event, no audit row. The monitor keeps doing
|
|
877
|
+
* exactly what it was doing.
|
|
878
|
+
*/
|
|
879
|
+
it("is adopted without running the monitor update pipeline", async () => {
|
|
880
|
+
monitorTable = [
|
|
881
|
+
monitorRow({
|
|
882
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
883
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
884
|
+
}),
|
|
885
|
+
];
|
|
886
|
+
deviceTable = [device()];
|
|
887
|
+
policyTable = [policy()];
|
|
888
|
+
|
|
889
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
890
|
+
projectId: PROJECT_ID,
|
|
891
|
+
deviceId: DEVICE_ID,
|
|
892
|
+
});
|
|
893
|
+
|
|
894
|
+
expect(monitorStampMock).toHaveBeenCalledWith(
|
|
895
|
+
expect.objectContaining({
|
|
896
|
+
data: expect.objectContaining({
|
|
897
|
+
networkAlertPolicyId: expect.anything(),
|
|
898
|
+
}),
|
|
899
|
+
}),
|
|
900
|
+
);
|
|
901
|
+
expect(monitorUpdateByMock).not.toHaveBeenCalled();
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
/*
|
|
905
|
+
* A monitor another policy owns is not adoptable and not deletable. The
|
|
906
|
+
* one-policy-per-template rule makes this unreachable through the API, but
|
|
907
|
+
* the engine must never be the thing that turns a data anomaly into a lost
|
|
908
|
+
* monitor.
|
|
909
|
+
*/
|
|
910
|
+
it("is left alone when a different policy already owns it", async () => {
|
|
911
|
+
const foreign: Monitor = monitorRow({
|
|
912
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
913
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
914
|
+
networkAlertPolicyId: OTHER_POLICY_ID,
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
monitorTable = [foreign];
|
|
918
|
+
deviceTable = [device()];
|
|
919
|
+
policyTable = [
|
|
920
|
+
policy(),
|
|
921
|
+
policy(
|
|
922
|
+
{ name: "Other", scope: { siteIds: [SITE_ID.toString()] } },
|
|
923
|
+
OTHER_POLICY_ID,
|
|
924
|
+
),
|
|
925
|
+
];
|
|
926
|
+
|
|
927
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
928
|
+
projectId: PROJECT_ID,
|
|
929
|
+
deviceId: DEVICE_ID,
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
expect(foreign.networkAlertPolicyId?.toString()).toBe(
|
|
933
|
+
OTHER_POLICY_ID.toString(),
|
|
934
|
+
);
|
|
935
|
+
expect(monitorTable).toContain(foreign);
|
|
936
|
+
});
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
/*
|
|
940
|
+
* Provisionability is a property of the DEVICE, and losing it removes every
|
|
941
|
+
* policy monitor. The monitor-backed case is the one that matters most: the
|
|
942
|
+
* device's health is now a bound monitor's, nothing polls it, and a Network
|
|
943
|
+
* Device monitor left behind is billed for a verdict that will never arrive.
|
|
944
|
+
*/
|
|
945
|
+
describe("a device that stops being provisionable", () => {
|
|
946
|
+
async function reconcileAfter(
|
|
947
|
+
change: Partial<NetworkDevice>,
|
|
948
|
+
): Promise<Array<Monitor>> {
|
|
949
|
+
deviceTable = [device()];
|
|
950
|
+
policyTable = [policy()];
|
|
951
|
+
|
|
952
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
953
|
+
projectId: PROJECT_ID,
|
|
954
|
+
deviceId: DEVICE_ID,
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
expect(monitorsOfDevice()).toHaveLength(1);
|
|
958
|
+
|
|
959
|
+
Object.assign(deviceTable[0]!, change);
|
|
960
|
+
|
|
961
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
962
|
+
projectId: PROJECT_ID,
|
|
963
|
+
deviceId: DEVICE_ID,
|
|
964
|
+
});
|
|
965
|
+
|
|
966
|
+
return monitorsOfDevice();
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
it("loses its policy monitors when it becomes monitor-backed", async () => {
|
|
970
|
+
expect(
|
|
971
|
+
await reconcileAfter({
|
|
972
|
+
monitoringMethod: NetworkDeviceMonitoringMethod.Monitor,
|
|
973
|
+
}),
|
|
974
|
+
).toHaveLength(0);
|
|
975
|
+
});
|
|
976
|
+
|
|
977
|
+
it("loses its policy monitors when it is archived", async () => {
|
|
978
|
+
expect(await reconcileAfter({ isArchived: true })).toHaveLength(0);
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
/*
|
|
982
|
+
* A device with no probe is polled by nothing, so its monitor would sit
|
|
983
|
+
* Pending forever — and still be billed.
|
|
984
|
+
*/
|
|
985
|
+
it("loses its policy monitors when its probe is cleared", async () => {
|
|
986
|
+
expect(
|
|
987
|
+
await reconcileAfter({ probeId: undefined as unknown as ObjectID }),
|
|
988
|
+
).toHaveLength(0);
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
it("gets them back when it becomes probe-polled again", async () => {
|
|
992
|
+
deviceTable = [
|
|
993
|
+
device({ monitoringMethod: NetworkDeviceMonitoringMethod.Monitor }),
|
|
994
|
+
];
|
|
995
|
+
policyTable = [policy()];
|
|
996
|
+
|
|
997
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
998
|
+
projectId: PROJECT_ID,
|
|
999
|
+
deviceId: DEVICE_ID,
|
|
1000
|
+
});
|
|
1001
|
+
|
|
1002
|
+
expect(monitorsOfDevice()).toHaveLength(0);
|
|
1003
|
+
|
|
1004
|
+
deviceTable[0]!.monitoringMethod = NetworkDeviceMonitoringMethod.Probe;
|
|
1005
|
+
|
|
1006
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1007
|
+
projectId: PROJECT_ID,
|
|
1008
|
+
deviceId: DEVICE_ID,
|
|
1009
|
+
});
|
|
1010
|
+
|
|
1011
|
+
expect(monitorsOfDevice()).toHaveLength(1);
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
/*
|
|
1015
|
+
* The legacy free-text values — NULL, "" and "SNMP" — all mean "the probe
|
|
1016
|
+
* polls it". A device written before ping-first polling must not be read
|
|
1017
|
+
* as monitor-backed and quietly stripped of its alerting.
|
|
1018
|
+
*/
|
|
1019
|
+
it("treats a legacy SNMP monitoringMethod as probe-polled", async () => {
|
|
1020
|
+
deviceTable = [device({ monitoringMethod: "SNMP" })];
|
|
1021
|
+
policyTable = [policy()];
|
|
1022
|
+
|
|
1023
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1024
|
+
projectId: PROJECT_ID,
|
|
1025
|
+
deviceId: DEVICE_ID,
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
expect(monitorsOfDevice()).toHaveLength(1);
|
|
1029
|
+
});
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
describe("a disabled policy", () => {
|
|
1033
|
+
it("keeps its monitors and pauses them rather than deleting them", async () => {
|
|
1034
|
+
deviceTable = [device()];
|
|
1035
|
+
policyTable = [policy()];
|
|
1036
|
+
|
|
1037
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1038
|
+
projectId: PROJECT_ID,
|
|
1039
|
+
deviceId: DEVICE_ID,
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
policyTable[0]!.isEnabled = false;
|
|
1043
|
+
|
|
1044
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1045
|
+
projectId: PROJECT_ID,
|
|
1046
|
+
deviceId: DEVICE_ID,
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
/*
|
|
1050
|
+
* The row survives — with its id, its incident history and its
|
|
1051
|
+
* dependencies — which is the whole difference between pausing a policy
|
|
1052
|
+
* and deleting one.
|
|
1053
|
+
*/
|
|
1054
|
+
expect(monitorsOfDevice()).toHaveLength(1);
|
|
1055
|
+
expect(monitorsOfDevice()[0]!.disableActiveMonitoring).toBe(true);
|
|
1056
|
+
});
|
|
1057
|
+
|
|
1058
|
+
it("provisions nothing new while it is off", async () => {
|
|
1059
|
+
deviceTable = [device()];
|
|
1060
|
+
policyTable = [policy({ isEnabled: false })];
|
|
1061
|
+
|
|
1062
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1063
|
+
projectId: PROJECT_ID,
|
|
1064
|
+
deviceId: DEVICE_ID,
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
expect(monitorCreateMock).not.toHaveBeenCalled();
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
/*
|
|
1071
|
+
* A template-less policy — only reachable through the FK's SET NULL
|
|
1072
|
+
* backstop, because MonitorTemplateService refuses to delete a template a
|
|
1073
|
+
* policy uses — is treated exactly like a disabled one. Nothing to
|
|
1074
|
+
* provision from, so nothing is provisioned and nothing is destroyed.
|
|
1075
|
+
*/
|
|
1076
|
+
it("behaves the same when its template was deleted out from under it", async () => {
|
|
1077
|
+
deviceTable = [device()];
|
|
1078
|
+
policyTable = [policy()];
|
|
1079
|
+
|
|
1080
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1081
|
+
projectId: PROJECT_ID,
|
|
1082
|
+
deviceId: DEVICE_ID,
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
delete policyTable[0]!.monitorTemplateId;
|
|
1086
|
+
|
|
1087
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1088
|
+
projectId: PROJECT_ID,
|
|
1089
|
+
deviceId: DEVICE_ID,
|
|
1090
|
+
});
|
|
1091
|
+
|
|
1092
|
+
expect(monitorsOfDevice()).toHaveLength(1);
|
|
1093
|
+
});
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
/*
|
|
1097
|
+
* Re-pointing a policy at a different template is a re-clone: the monitors
|
|
1098
|
+
* from the old template are the old alerting configuration and must go, and
|
|
1099
|
+
* new ones are provisioned from the template the policy names now. This is
|
|
1100
|
+
* why ownership is the pair, not the policy id alone.
|
|
1101
|
+
*/
|
|
1102
|
+
describe("a policy re-pointed at a different template", () => {
|
|
1103
|
+
it("replaces the monitors made from the old template", async () => {
|
|
1104
|
+
deviceTable = [device()];
|
|
1105
|
+
policyTable = [policy()];
|
|
1106
|
+
|
|
1107
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1108
|
+
projectId: PROJECT_ID,
|
|
1109
|
+
deviceId: DEVICE_ID,
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
const originalMonitorId: string = monitorsOfDevice()[0]!.id!.toString();
|
|
1113
|
+
|
|
1114
|
+
policyTable[0]!.monitorTemplateId = OTHER_TEMPLATE_ID;
|
|
1115
|
+
|
|
1116
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1117
|
+
projectId: PROJECT_ID,
|
|
1118
|
+
deviceId: DEVICE_ID,
|
|
1119
|
+
});
|
|
1120
|
+
|
|
1121
|
+
const survivors: Array<Monitor> = monitorsOfDevice();
|
|
1122
|
+
|
|
1123
|
+
expect(survivors).toHaveLength(1);
|
|
1124
|
+
expect(survivors[0]!.id!.toString()).not.toBe(originalMonitorId);
|
|
1125
|
+
expect(survivors[0]!.monitorTemplateId?.toString()).toBe(
|
|
1126
|
+
OTHER_TEMPLATE_ID.toString(),
|
|
1127
|
+
);
|
|
1128
|
+
});
|
|
1129
|
+
});
|
|
1130
|
+
|
|
1131
|
+
/*
|
|
1132
|
+
* A monitor whose owning policy row is gone is nobody's. In practice the
|
|
1133
|
+
* policy delete path removed it already; this is the backstop for the row
|
|
1134
|
+
* that outlived it, and without it that monitor would be billed forever with
|
|
1135
|
+
* nothing left to explain it.
|
|
1136
|
+
*/
|
|
1137
|
+
describe("a monitor whose policy no longer exists", () => {
|
|
1138
|
+
it("is removed on the next pass", async () => {
|
|
1139
|
+
monitorTable = [
|
|
1140
|
+
monitorRow({
|
|
1141
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
1142
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
1143
|
+
networkAlertPolicyId: OTHER_POLICY_ID,
|
|
1144
|
+
}),
|
|
1145
|
+
];
|
|
1146
|
+
deviceTable = [device()];
|
|
1147
|
+
policyTable = [];
|
|
1148
|
+
|
|
1149
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1150
|
+
projectId: PROJECT_ID,
|
|
1151
|
+
deviceId: DEVICE_ID,
|
|
1152
|
+
});
|
|
1153
|
+
|
|
1154
|
+
expect(monitorsOfDevice()).toHaveLength(0);
|
|
1155
|
+
});
|
|
1156
|
+
});
|
|
1157
|
+
|
|
1158
|
+
describe("the per-device lock", () => {
|
|
1159
|
+
it("is taken on the device, by name, before anything is read", async () => {
|
|
1160
|
+
deviceTable = [device()];
|
|
1161
|
+
policyTable = [policy()];
|
|
1162
|
+
|
|
1163
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1164
|
+
projectId: PROJECT_ID,
|
|
1165
|
+
deviceId: DEVICE_ID,
|
|
1166
|
+
});
|
|
1167
|
+
|
|
1168
|
+
expect(semaphoreLockMock).toHaveBeenCalledWith(
|
|
1169
|
+
expect.objectContaining({
|
|
1170
|
+
key: policyDeviceLockKey(DEVICE_ID),
|
|
1171
|
+
namespace: POLICY_DEVICE_LOCK_NAMESPACE,
|
|
1172
|
+
/*
|
|
1173
|
+
* One attempt, never a queue: whoever holds it is computing the same
|
|
1174
|
+
* difference from fresher data than this pass would.
|
|
1175
|
+
*/
|
|
1176
|
+
acquireAttemptsLimit: 1,
|
|
1177
|
+
}),
|
|
1178
|
+
);
|
|
1179
|
+
expect(policyDeviceLockKey(DEVICE_ID)).toBe(
|
|
1180
|
+
`NetworkAlertPolicy:Device:${DEVICE_ID.toString()}`,
|
|
1181
|
+
);
|
|
1182
|
+
});
|
|
1183
|
+
|
|
1184
|
+
/*
|
|
1185
|
+
* A pass that cannot take the lock does NOTHING — it does not read, and
|
|
1186
|
+
* above all it does not write. That is what makes "two policies racing on
|
|
1187
|
+
* one device" safe: the loser of the race is not a second writer, it is a
|
|
1188
|
+
* no-op.
|
|
1189
|
+
*/
|
|
1190
|
+
it("makes a pass that cannot acquire it a complete no-op", async () => {
|
|
1191
|
+
deviceTable = [device()];
|
|
1192
|
+
policyTable = [policy()];
|
|
1193
|
+
semaphoreLockMock.mockRejectedValue(new Error("lock held"));
|
|
1194
|
+
|
|
1195
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1196
|
+
projectId: PROJECT_ID,
|
|
1197
|
+
deviceId: DEVICE_ID,
|
|
1198
|
+
});
|
|
1199
|
+
|
|
1200
|
+
expect(deviceFindOneByMock).not.toHaveBeenCalled();
|
|
1201
|
+
expect(monitorCreateMock).not.toHaveBeenCalled();
|
|
1202
|
+
expect(monitorDeleteByMock).not.toHaveBeenCalled();
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1205
|
+
it("is released even when the reconciliation throws", async () => {
|
|
1206
|
+
deviceTable = [device()];
|
|
1207
|
+
policyTable = [policy()];
|
|
1208
|
+
deviceFindOneByMock.mockRejectedValue(new Error("database is on fire"));
|
|
1209
|
+
|
|
1210
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1211
|
+
projectId: PROJECT_ID,
|
|
1212
|
+
deviceId: DEVICE_ID,
|
|
1213
|
+
});
|
|
1214
|
+
|
|
1215
|
+
expect(semaphoreReleaseMock).toHaveBeenCalledWith(FAKE_MUTEX);
|
|
1216
|
+
});
|
|
1217
|
+
|
|
1218
|
+
/*
|
|
1219
|
+
* ...and the throw is recorded rather than propagated. reconcileDevice is
|
|
1220
|
+
* called from a device create's detached chain; a template that stopped
|
|
1221
|
+
* validating must not become a failed device import.
|
|
1222
|
+
*/
|
|
1223
|
+
it("records the failure instead of throwing it at the caller", async () => {
|
|
1224
|
+
deviceTable = [device()];
|
|
1225
|
+
policyTable = [policy()];
|
|
1226
|
+
deviceFindOneByMock.mockRejectedValue(new Error("database is on fire"));
|
|
1227
|
+
|
|
1228
|
+
const context: PolicyRunContext =
|
|
1229
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1230
|
+
projectId: PROJECT_ID,
|
|
1231
|
+
deviceId: DEVICE_ID,
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
expect(context.failures[0]).toContain("database is on fire");
|
|
1235
|
+
});
|
|
1236
|
+
});
|
|
1237
|
+
|
|
1238
|
+
/*
|
|
1239
|
+
* Prerequisite 5. A project whose plan cannot hold another monitor must
|
|
1240
|
+
* produce ONE message an operator can act on, not five hundred identical
|
|
1241
|
+
* create failures — and the run must stop, because every remaining create
|
|
1242
|
+
* would fail the same way.
|
|
1243
|
+
*/
|
|
1244
|
+
describe("the plan check", () => {
|
|
1245
|
+
it("stops the run before the first create when the subscription is unpaid", async () => {
|
|
1246
|
+
deviceTable = [device()];
|
|
1247
|
+
policyTable = [policy()];
|
|
1248
|
+
currentPlanMock.mockResolvedValue({
|
|
1249
|
+
plan: PlanType.Growth,
|
|
1250
|
+
isSubscriptionUnpaid: true,
|
|
1251
|
+
});
|
|
1252
|
+
|
|
1253
|
+
const context: PolicyRunContext =
|
|
1254
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1255
|
+
projectId: PROJECT_ID,
|
|
1256
|
+
deviceId: DEVICE_ID,
|
|
1257
|
+
});
|
|
1258
|
+
|
|
1259
|
+
expect(monitorCreateMock).not.toHaveBeenCalled();
|
|
1260
|
+
expect(context.isStopped).toBe(true);
|
|
1261
|
+
expect(context.planException).toContain("subscription is unpaid");
|
|
1262
|
+
});
|
|
1263
|
+
|
|
1264
|
+
it("stops the run when the free plan's monitor limit is already reached", async () => {
|
|
1265
|
+
deviceTable = [device()];
|
|
1266
|
+
policyTable = [policy()];
|
|
1267
|
+
currentPlanMock.mockResolvedValue({
|
|
1268
|
+
plan: PlanType.Free,
|
|
1269
|
+
isSubscriptionUnpaid: false,
|
|
1270
|
+
});
|
|
1271
|
+
monitorCountByMock.mockResolvedValue(new PositiveNumber(10));
|
|
1272
|
+
|
|
1273
|
+
const context: PolicyRunContext =
|
|
1274
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1275
|
+
projectId: PROJECT_ID,
|
|
1276
|
+
deviceId: DEVICE_ID,
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
expect(monitorCreateMock).not.toHaveBeenCalled();
|
|
1280
|
+
expect(context.planException).toContain("free plan");
|
|
1281
|
+
});
|
|
1282
|
+
|
|
1283
|
+
/*
|
|
1284
|
+
* Asked ONCE per run. Fifty devices in one sweep must not be fifty billing
|
|
1285
|
+
* lookups; that is the difference between a five-minute sweep and a
|
|
1286
|
+
* five-minute outage.
|
|
1287
|
+
*/
|
|
1288
|
+
it("asks the plan once for a whole run", async () => {
|
|
1289
|
+
deviceTable = [device(), device({}, OTHER_DEVICE_ID)];
|
|
1290
|
+
policyTable = [policy()];
|
|
1291
|
+
|
|
1292
|
+
const context: PolicyRunContext =
|
|
1293
|
+
NetworkAlertPolicyEngineService.createRunContext(PROJECT_ID);
|
|
1294
|
+
|
|
1295
|
+
await NetworkAlertPolicyEngineService.reconcileDevices({
|
|
1296
|
+
projectId: PROJECT_ID,
|
|
1297
|
+
deviceIds: [DEVICE_ID, OTHER_DEVICE_ID],
|
|
1298
|
+
context: context,
|
|
1299
|
+
});
|
|
1300
|
+
|
|
1301
|
+
expect(monitorCreateMock).toHaveBeenCalledTimes(2);
|
|
1302
|
+
expect(currentPlanMock).toHaveBeenCalledTimes(1);
|
|
1303
|
+
});
|
|
1304
|
+
|
|
1305
|
+
/*
|
|
1306
|
+
* The ceiling can be crossed DURING a run: the precheck passed at nine of
|
|
1307
|
+
* ten monitors and the tenth create is the one that is refused. The verdict
|
|
1308
|
+
* is re-asked after a failed create — never pattern-matched out of the
|
|
1309
|
+
* error text, which would drift the moment MonitorService reworded its
|
|
1310
|
+
* refusal — and the run stops at the first refusal instead of the five
|
|
1311
|
+
* hundredth.
|
|
1312
|
+
*/
|
|
1313
|
+
it("stops mid-run when a create fails and the plan now refuses another monitor", async () => {
|
|
1314
|
+
deviceTable = [device(), device({}, OTHER_DEVICE_ID)];
|
|
1315
|
+
policyTable = [policy()];
|
|
1316
|
+
currentPlanMock.mockResolvedValue({
|
|
1317
|
+
plan: PlanType.Free,
|
|
1318
|
+
isSubscriptionUnpaid: false,
|
|
1319
|
+
});
|
|
1320
|
+
monitorCountByMock
|
|
1321
|
+
.mockResolvedValueOnce(new PositiveNumber(9))
|
|
1322
|
+
.mockResolvedValue(new PositiveNumber(10));
|
|
1323
|
+
monitorCreateMock.mockRejectedValueOnce(
|
|
1324
|
+
new BadDataException("monitor limit reached"),
|
|
1325
|
+
);
|
|
1326
|
+
|
|
1327
|
+
const context: PolicyRunContext =
|
|
1328
|
+
NetworkAlertPolicyEngineService.createRunContext(PROJECT_ID);
|
|
1329
|
+
|
|
1330
|
+
await NetworkAlertPolicyEngineService.reconcileDevices({
|
|
1331
|
+
projectId: PROJECT_ID,
|
|
1332
|
+
deviceIds: [DEVICE_ID, OTHER_DEVICE_ID],
|
|
1333
|
+
context: context,
|
|
1334
|
+
});
|
|
1335
|
+
|
|
1336
|
+
expect(context.isStopped).toBe(true);
|
|
1337
|
+
expect(context.planException).toContain("free plan");
|
|
1338
|
+
// The second device was never attempted.
|
|
1339
|
+
expect(monitorCreateMock).toHaveBeenCalledTimes(1);
|
|
1340
|
+
});
|
|
1341
|
+
|
|
1342
|
+
/*
|
|
1343
|
+
* A billing lookup that FAILS is not a plan refusal. A Stripe blip must not
|
|
1344
|
+
* stop a fleet from being provisioned; it is recorded and the run carries
|
|
1345
|
+
* on.
|
|
1346
|
+
*/
|
|
1347
|
+
it("treats a billing lookup failure as an ordinary failure, not a refusal", async () => {
|
|
1348
|
+
deviceTable = [device()];
|
|
1349
|
+
policyTable = [policy()];
|
|
1350
|
+
currentPlanMock.mockRejectedValue(new Error("stripe timed out"));
|
|
1351
|
+
|
|
1352
|
+
const context: PolicyRunContext =
|
|
1353
|
+
await NetworkAlertPolicyEngineService.reconcileDevice({
|
|
1354
|
+
projectId: PROJECT_ID,
|
|
1355
|
+
deviceId: DEVICE_ID,
|
|
1356
|
+
});
|
|
1357
|
+
|
|
1358
|
+
expect(context.isStopped).toBe(false);
|
|
1359
|
+
expect(context.failures[0]).toContain("stripe timed out");
|
|
1360
|
+
expect(monitorCreateMock).toHaveBeenCalledTimes(1);
|
|
1361
|
+
});
|
|
1362
|
+
});
|
|
1363
|
+
|
|
1364
|
+
describe("the run's monitor budget", () => {
|
|
1365
|
+
it("stops writing once MAX_MONITORS_PER_POLICY_SYNC monitors have been written", async () => {
|
|
1366
|
+
deviceTable = [device(), device({}, OTHER_DEVICE_ID)];
|
|
1367
|
+
policyTable = [policy()];
|
|
1368
|
+
|
|
1369
|
+
const context: PolicyRunContext =
|
|
1370
|
+
NetworkAlertPolicyEngineService.createRunContext(PROJECT_ID, 1);
|
|
1371
|
+
|
|
1372
|
+
await NetworkAlertPolicyEngineService.reconcileDevices({
|
|
1373
|
+
projectId: PROJECT_ID,
|
|
1374
|
+
deviceIds: [DEVICE_ID, OTHER_DEVICE_ID],
|
|
1375
|
+
context: context,
|
|
1376
|
+
});
|
|
1377
|
+
|
|
1378
|
+
/*
|
|
1379
|
+
* One monitor, and the run marked truncated rather than failed: nothing
|
|
1380
|
+
* is half-written, and the next sweep computes the same difference and
|
|
1381
|
+
* continues.
|
|
1382
|
+
*/
|
|
1383
|
+
expect(monitorCreateMock).toHaveBeenCalledTimes(1);
|
|
1384
|
+
expect(context.isTruncated).toBe(true);
|
|
1385
|
+
expect(context.failures).toHaveLength(0);
|
|
1386
|
+
});
|
|
1387
|
+
|
|
1388
|
+
it("defaults to the documented cap", () => {
|
|
1389
|
+
expect(
|
|
1390
|
+
NetworkAlertPolicyEngineService.createRunContext(PROJECT_ID)
|
|
1391
|
+
.monitorBudget,
|
|
1392
|
+
).toBe(MAX_MONITORS_PER_POLICY_SYNC);
|
|
1393
|
+
});
|
|
1394
|
+
});
|
|
1395
|
+
|
|
1396
|
+
describe("syncPolicy over a policy's whole fleet", () => {
|
|
1397
|
+
it("provisions every matching device and stamps the covered count", async () => {
|
|
1398
|
+
deviceTable = [device(), device({}, OTHER_DEVICE_ID)];
|
|
1399
|
+
policyTable = [policy()];
|
|
1400
|
+
|
|
1401
|
+
await NetworkAlertPolicyEngineService.syncPolicy({ policyId: POLICY_ID });
|
|
1402
|
+
|
|
1403
|
+
expect(monitorTable).toHaveLength(2);
|
|
1404
|
+
expect(policyStampMock).toHaveBeenCalledWith(
|
|
1405
|
+
expect.objectContaining({
|
|
1406
|
+
id: POLICY_ID,
|
|
1407
|
+
data: expect.objectContaining({
|
|
1408
|
+
coveredDeviceCount: 2,
|
|
1409
|
+
lastSyncError: null,
|
|
1410
|
+
}),
|
|
1411
|
+
}),
|
|
1412
|
+
);
|
|
1413
|
+
});
|
|
1414
|
+
|
|
1415
|
+
/*
|
|
1416
|
+
* The covered count is what the settings table prints beside the scope
|
|
1417
|
+
* sentence, so it counts the devices the policy actually provisions for —
|
|
1418
|
+
* not every device the scope's SQL half matches. An archived or
|
|
1419
|
+
* monitor-backed device is in the site, and gets no monitor.
|
|
1420
|
+
*/
|
|
1421
|
+
it("counts only the devices it can actually provision for", async () => {
|
|
1422
|
+
deviceTable = [
|
|
1423
|
+
device(),
|
|
1424
|
+
device(
|
|
1425
|
+
{ monitoringMethod: NetworkDeviceMonitoringMethod.Monitor },
|
|
1426
|
+
OTHER_DEVICE_ID,
|
|
1427
|
+
),
|
|
1428
|
+
];
|
|
1429
|
+
policyTable = [policy()];
|
|
1430
|
+
|
|
1431
|
+
await NetworkAlertPolicyEngineService.syncPolicy({ policyId: POLICY_ID });
|
|
1432
|
+
|
|
1433
|
+
expect(policyStampMock).toHaveBeenCalledWith(
|
|
1434
|
+
expect.objectContaining({
|
|
1435
|
+
data: expect.objectContaining({ coveredDeviceCount: 1 }),
|
|
1436
|
+
}),
|
|
1437
|
+
);
|
|
1438
|
+
});
|
|
1439
|
+
|
|
1440
|
+
it("removes the monitors of devices that have left the scope", async () => {
|
|
1441
|
+
deviceTable = [device(), device({}, OTHER_DEVICE_ID)];
|
|
1442
|
+
policyTable = [policy()];
|
|
1443
|
+
|
|
1444
|
+
await NetworkAlertPolicyEngineService.syncPolicy({ policyId: POLICY_ID });
|
|
1445
|
+
expect(monitorTable).toHaveLength(2);
|
|
1446
|
+
|
|
1447
|
+
// The second device moves to a site the policy does not cover.
|
|
1448
|
+
deviceTable[1]!.siteId = OTHER_SITE_ID;
|
|
1449
|
+
policyTable[0]!.scope = {
|
|
1450
|
+
siteIds: [SITE_ID.toString()],
|
|
1451
|
+
} as NetworkAlertPolicyScope;
|
|
1452
|
+
|
|
1453
|
+
await NetworkAlertPolicyEngineService.syncPolicy({ policyId: POLICY_ID });
|
|
1454
|
+
|
|
1455
|
+
expect(monitorTable).toHaveLength(1);
|
|
1456
|
+
expect(monitorTable[0]!.autoProvisionedNetworkDeviceId?.toString()).toBe(
|
|
1457
|
+
DEVICE_ID.toString(),
|
|
1458
|
+
);
|
|
1459
|
+
});
|
|
1460
|
+
|
|
1461
|
+
it("records a failure in lastSyncError where the operator will see it", async () => {
|
|
1462
|
+
deviceTable = [device()];
|
|
1463
|
+
policyTable = [policy()];
|
|
1464
|
+
// The template vanished between the policy's save and this pass.
|
|
1465
|
+
templateFindOneByMock.mockResolvedValue(null);
|
|
1466
|
+
|
|
1467
|
+
await NetworkAlertPolicyEngineService.syncPolicy({ policyId: POLICY_ID });
|
|
1468
|
+
|
|
1469
|
+
expect(policyStampMock).toHaveBeenCalledWith(
|
|
1470
|
+
expect.objectContaining({
|
|
1471
|
+
data: expect.objectContaining({
|
|
1472
|
+
lastSyncError: expect.stringContaining("Monitor template"),
|
|
1473
|
+
}),
|
|
1474
|
+
}),
|
|
1475
|
+
);
|
|
1476
|
+
});
|
|
1477
|
+
|
|
1478
|
+
/*
|
|
1479
|
+
* A disabled policy is looked at and found to have nothing to do. Stamping
|
|
1480
|
+
* lastSyncAt for it is honest — and leaving lastSyncError null is what
|
|
1481
|
+
* stops the settings table showing a red row for a policy somebody
|
|
1482
|
+
* deliberately switched off.
|
|
1483
|
+
*/
|
|
1484
|
+
it("stamps a disabled policy without touching a single monitor", async () => {
|
|
1485
|
+
deviceTable = [device()];
|
|
1486
|
+
policyTable = [policy({ isEnabled: false })];
|
|
1487
|
+
|
|
1488
|
+
await NetworkAlertPolicyEngineService.syncPolicy({ policyId: POLICY_ID });
|
|
1489
|
+
|
|
1490
|
+
expect(monitorCreateMock).not.toHaveBeenCalled();
|
|
1491
|
+
expect(monitorDeleteByMock).not.toHaveBeenCalled();
|
|
1492
|
+
expect(policyStampMock).toHaveBeenCalledWith(
|
|
1493
|
+
expect.objectContaining({
|
|
1494
|
+
data: expect.objectContaining({ lastSyncError: null }),
|
|
1495
|
+
}),
|
|
1496
|
+
);
|
|
1497
|
+
});
|
|
1498
|
+
|
|
1499
|
+
it("does nothing at all for a policy that has been deleted", async () => {
|
|
1500
|
+
policyTable = [];
|
|
1501
|
+
|
|
1502
|
+
await expect(
|
|
1503
|
+
NetworkAlertPolicyEngineService.syncPolicy({ policyId: POLICY_ID }),
|
|
1504
|
+
).resolves.toBeNull();
|
|
1505
|
+
|
|
1506
|
+
expect(policyStampMock).not.toHaveBeenCalled();
|
|
1507
|
+
});
|
|
1508
|
+
|
|
1509
|
+
/*
|
|
1510
|
+
* templateSyncedAt means "every monitor this policy owns is running the
|
|
1511
|
+
* template's current configuration". A sweep that changed nothing has
|
|
1512
|
+
* re-synced nothing, so it must not stamp it — otherwise an operator would
|
|
1513
|
+
* read "Template Synced: 2 minutes ago" and believe a criteria edit they
|
|
1514
|
+
* made an hour ago had landed.
|
|
1515
|
+
*/
|
|
1516
|
+
it("does not stamp templateSyncedAt on an ordinary sweep", async () => {
|
|
1517
|
+
deviceTable = [device()];
|
|
1518
|
+
policyTable = [policy()];
|
|
1519
|
+
|
|
1520
|
+
await NetworkAlertPolicyEngineService.syncPolicy({ policyId: POLICY_ID });
|
|
1521
|
+
|
|
1522
|
+
const stamped: Record<string, unknown> = (
|
|
1523
|
+
policyStampMock.mock.calls[0]![0] as { data: Record<string, unknown> }
|
|
1524
|
+
).data;
|
|
1525
|
+
|
|
1526
|
+
expect(stamped["templateSyncedAt"]).toBeUndefined();
|
|
1527
|
+
});
|
|
1528
|
+
|
|
1529
|
+
it("stamps templateSyncedAt when the fleet was rebuilt from a new template", async () => {
|
|
1530
|
+
deviceTable = [device()];
|
|
1531
|
+
policyTable = [policy()];
|
|
1532
|
+
|
|
1533
|
+
await NetworkAlertPolicyEngineService.syncPolicy({
|
|
1534
|
+
policyId: POLICY_ID,
|
|
1535
|
+
stampTemplateSyncedOnCleanPass: true,
|
|
1536
|
+
});
|
|
1537
|
+
|
|
1538
|
+
const stamped: Record<string, unknown> = (
|
|
1539
|
+
policyStampMock.mock.calls[0]![0] as { data: Record<string, unknown> }
|
|
1540
|
+
).data;
|
|
1541
|
+
|
|
1542
|
+
expect(stamped["templateSyncedAt"]).toBeInstanceOf(Date);
|
|
1543
|
+
});
|
|
1544
|
+
|
|
1545
|
+
/*
|
|
1546
|
+
* ...but not when the pass ADOPTED a monitor. An adopted monitor was built
|
|
1547
|
+
* by somebody else and its criteria are not this template's, so claiming
|
|
1548
|
+
* the fleet is in step with the template would be false.
|
|
1549
|
+
*/
|
|
1550
|
+
it("does not stamp templateSyncedAt for a pass that adopted a monitor", async () => {
|
|
1551
|
+
monitorTable = [
|
|
1552
|
+
monitorRow({
|
|
1553
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
1554
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
1555
|
+
}),
|
|
1556
|
+
];
|
|
1557
|
+
deviceTable = [device()];
|
|
1558
|
+
policyTable = [policy()];
|
|
1559
|
+
|
|
1560
|
+
await NetworkAlertPolicyEngineService.syncPolicy({
|
|
1561
|
+
policyId: POLICY_ID,
|
|
1562
|
+
stampTemplateSyncedOnCleanPass: true,
|
|
1563
|
+
});
|
|
1564
|
+
|
|
1565
|
+
const stamped: Record<string, unknown> = (
|
|
1566
|
+
policyStampMock.mock.calls[0]![0] as { data: Record<string, unknown> }
|
|
1567
|
+
).data;
|
|
1568
|
+
|
|
1569
|
+
expect(stamped["templateSyncedAt"]).toBeUndefined();
|
|
1570
|
+
});
|
|
1571
|
+
});
|
|
1572
|
+
|
|
1573
|
+
/*
|
|
1574
|
+
* Prerequisite 9's engine half. A scope is validated at write, so a stale or
|
|
1575
|
+
* malformed id only ever arrives here through a hand-edited row — and the
|
|
1576
|
+
* engine's answer is "match nothing", never "throw" and never "match
|
|
1577
|
+
* everything".
|
|
1578
|
+
*/
|
|
1579
|
+
describe("scope ids the engine cannot use", () => {
|
|
1580
|
+
it("matches nothing when a kind holds only unusable ids", async () => {
|
|
1581
|
+
deviceTable = [device()];
|
|
1582
|
+
policyTable = [
|
|
1583
|
+
policy({
|
|
1584
|
+
scope: { siteIds: ["not-a-uuid"] } as NetworkAlertPolicyScope,
|
|
1585
|
+
}),
|
|
1586
|
+
];
|
|
1587
|
+
|
|
1588
|
+
await NetworkAlertPolicyEngineService.syncPolicy({ policyId: POLICY_ID });
|
|
1589
|
+
|
|
1590
|
+
/*
|
|
1591
|
+
* Dropping the last unusable id and leaving the kind EMPTY would be the
|
|
1592
|
+
* dangerous bug: an empty kind matches every device, so a typo'd scope
|
|
1593
|
+
* would silently provision the whole estate.
|
|
1594
|
+
*/
|
|
1595
|
+
expect(monitorCreateMock).not.toHaveBeenCalled();
|
|
1596
|
+
});
|
|
1597
|
+
|
|
1598
|
+
it("adds no clause at all for a kind that is genuinely empty", async () => {
|
|
1599
|
+
deviceTable = [device()];
|
|
1600
|
+
policyTable = [policy({ scope: {} as NetworkAlertPolicyScope })];
|
|
1601
|
+
|
|
1602
|
+
await NetworkAlertPolicyEngineService.syncPolicy({ policyId: POLICY_ID });
|
|
1603
|
+
|
|
1604
|
+
const deviceQuery: Record<string, unknown> = (
|
|
1605
|
+
deviceFindByMock.mock.calls[0]![0] as { query: Record<string, unknown> }
|
|
1606
|
+
).query;
|
|
1607
|
+
|
|
1608
|
+
expect(deviceQuery["siteId"]).toBeUndefined();
|
|
1609
|
+
expect(deviceQuery["networkDeviceRoleId"]).toBeUndefined();
|
|
1610
|
+
expect(deviceQuery["labels"]).toBeUndefined();
|
|
1611
|
+
expect(monitorCreateMock).toHaveBeenCalledTimes(1);
|
|
1612
|
+
});
|
|
1613
|
+
|
|
1614
|
+
// The engine reads a scope. It never writes one back.
|
|
1615
|
+
it("never rewrites the policy's scope", async () => {
|
|
1616
|
+
deviceTable = [device()];
|
|
1617
|
+
policyTable = [
|
|
1618
|
+
policy({
|
|
1619
|
+
scope: { siteIds: ["not-a-uuid"] } as NetworkAlertPolicyScope,
|
|
1620
|
+
}),
|
|
1621
|
+
];
|
|
1622
|
+
|
|
1623
|
+
await NetworkAlertPolicyEngineService.syncPolicy({ policyId: POLICY_ID });
|
|
1624
|
+
|
|
1625
|
+
for (const call of policyStampMock.mock.calls) {
|
|
1626
|
+
expect(
|
|
1627
|
+
(call[0] as { data: Record<string, unknown> }).data["scope"],
|
|
1628
|
+
).toBeUndefined();
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
expect(policyTable[0]!.scope).toEqual({ siteIds: ["not-a-uuid"] });
|
|
1632
|
+
});
|
|
1633
|
+
});
|
|
1634
|
+
|
|
1635
|
+
describe("deleting a policy", () => {
|
|
1636
|
+
it("removes exactly the monitors it owns, as root", async () => {
|
|
1637
|
+
const ownMonitor: Monitor = monitorRow({
|
|
1638
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
1639
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
1640
|
+
networkAlertPolicyId: POLICY_ID,
|
|
1641
|
+
});
|
|
1642
|
+
const otherPolicyMonitor: Monitor = monitorRow({
|
|
1643
|
+
autoProvisionedNetworkDeviceId: OTHER_DEVICE_ID,
|
|
1644
|
+
monitorTemplateId: OTHER_TEMPLATE_ID,
|
|
1645
|
+
networkAlertPolicyId: OTHER_POLICY_ID,
|
|
1646
|
+
});
|
|
1647
|
+
const handMade: Monitor = monitorRow({
|
|
1648
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
1649
|
+
monitorTemplateId: OTHER_TEMPLATE_ID,
|
|
1650
|
+
});
|
|
1651
|
+
|
|
1652
|
+
monitorTable = [ownMonitor, otherPolicyMonitor, handMade];
|
|
1653
|
+
|
|
1654
|
+
const deleted: number =
|
|
1655
|
+
await NetworkAlertPolicyEngineService.deleteMonitorsOwnedByPolicy({
|
|
1656
|
+
projectId: PROJECT_ID,
|
|
1657
|
+
policyId: POLICY_ID,
|
|
1658
|
+
});
|
|
1659
|
+
|
|
1660
|
+
expect(deleted).toBe(1);
|
|
1661
|
+
expect(monitorTable).toEqual([otherPolicyMonitor, handMade]);
|
|
1662
|
+
expect(monitorDeleteByMock).toHaveBeenCalledWith(
|
|
1663
|
+
expect.objectContaining({ props: { isRoot: true } }),
|
|
1664
|
+
);
|
|
1665
|
+
});
|
|
1666
|
+
|
|
1667
|
+
it("does nothing when the policy owns no monitors", async () => {
|
|
1668
|
+
monitorTable = [
|
|
1669
|
+
monitorRow({
|
|
1670
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
1671
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
1672
|
+
}),
|
|
1673
|
+
];
|
|
1674
|
+
|
|
1675
|
+
expect(
|
|
1676
|
+
await NetworkAlertPolicyEngineService.deleteMonitorsOwnedByPolicy({
|
|
1677
|
+
projectId: PROJECT_ID,
|
|
1678
|
+
policyId: POLICY_ID,
|
|
1679
|
+
}),
|
|
1680
|
+
).toBe(0);
|
|
1681
|
+
expect(monitorDeleteByMock).not.toHaveBeenCalled();
|
|
1682
|
+
});
|
|
1683
|
+
});
|
|
1684
|
+
|
|
1685
|
+
describe("deleting devices", () => {
|
|
1686
|
+
it("removes their policy-owned monitors and leaves the rest to the caller", async () => {
|
|
1687
|
+
const policyMonitor: Monitor = monitorRow({
|
|
1688
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
1689
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
1690
|
+
networkAlertPolicyId: POLICY_ID,
|
|
1691
|
+
});
|
|
1692
|
+
const ruleMonitor: Monitor = monitorRow({
|
|
1693
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
1694
|
+
monitorTemplateId: OTHER_TEMPLATE_ID,
|
|
1695
|
+
});
|
|
1696
|
+
|
|
1697
|
+
monitorTable = [policyMonitor, ruleMonitor];
|
|
1698
|
+
|
|
1699
|
+
const deleted: number =
|
|
1700
|
+
await NetworkAlertPolicyEngineService.deletePolicyMonitorsForDevices({
|
|
1701
|
+
projectId: PROJECT_ID,
|
|
1702
|
+
deviceIds: [DEVICE_ID],
|
|
1703
|
+
});
|
|
1704
|
+
|
|
1705
|
+
expect(deleted).toBe(1);
|
|
1706
|
+
/*
|
|
1707
|
+
* The auto-import rule's monitor survives this call: it is removed by
|
|
1708
|
+
* NetworkDeviceService's own preflight, under the caller's permissions,
|
|
1709
|
+
* because somebody chose that rule.
|
|
1710
|
+
*/
|
|
1711
|
+
expect(monitorTable).toEqual([ruleMonitor]);
|
|
1712
|
+
});
|
|
1713
|
+
|
|
1714
|
+
it("asks nothing when there are no devices", async () => {
|
|
1715
|
+
expect(
|
|
1716
|
+
await NetworkAlertPolicyEngineService.deletePolicyMonitorsForDevices({
|
|
1717
|
+
projectId: PROJECT_ID,
|
|
1718
|
+
deviceIds: [],
|
|
1719
|
+
}),
|
|
1720
|
+
).toBe(0);
|
|
1721
|
+
expect(monitorFindByMock).not.toHaveBeenCalled();
|
|
1722
|
+
});
|
|
1723
|
+
});
|
|
1724
|
+
|
|
1725
|
+
describe("pausing and resuming a policy's monitors", () => {
|
|
1726
|
+
beforeEach(() => {
|
|
1727
|
+
monitorTable = [
|
|
1728
|
+
monitorRow({
|
|
1729
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
1730
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
1731
|
+
networkAlertPolicyId: POLICY_ID,
|
|
1732
|
+
}),
|
|
1733
|
+
monitorRow({
|
|
1734
|
+
autoProvisionedNetworkDeviceId: OTHER_DEVICE_ID,
|
|
1735
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
1736
|
+
networkAlertPolicyId: POLICY_ID,
|
|
1737
|
+
}),
|
|
1738
|
+
// Another policy's monitor: never touched by this policy's pause.
|
|
1739
|
+
monitorRow({
|
|
1740
|
+
autoProvisionedNetworkDeviceId: DEVICE_ID,
|
|
1741
|
+
monitorTemplateId: OTHER_TEMPLATE_ID,
|
|
1742
|
+
networkAlertPolicyId: OTHER_POLICY_ID,
|
|
1743
|
+
}),
|
|
1744
|
+
];
|
|
1745
|
+
});
|
|
1746
|
+
|
|
1747
|
+
it("pauses only its own, and resuming reverses it exactly", async () => {
|
|
1748
|
+
await NetworkAlertPolicyEngineService.setPolicyMonitorsPaused({
|
|
1749
|
+
projectId: PROJECT_ID,
|
|
1750
|
+
policyId: POLICY_ID,
|
|
1751
|
+
isPaused: true,
|
|
1752
|
+
});
|
|
1753
|
+
|
|
1754
|
+
expect(monitorTable[0]!.disableActiveMonitoring).toBe(true);
|
|
1755
|
+
expect(monitorTable[1]!.disableActiveMonitoring).toBe(true);
|
|
1756
|
+
expect(monitorTable[2]!.disableActiveMonitoring).toBe(false);
|
|
1757
|
+
|
|
1758
|
+
await NetworkAlertPolicyEngineService.setPolicyMonitorsPaused({
|
|
1759
|
+
projectId: PROJECT_ID,
|
|
1760
|
+
policyId: POLICY_ID,
|
|
1761
|
+
isPaused: false,
|
|
1762
|
+
});
|
|
1763
|
+
|
|
1764
|
+
expect(monitorTable[0]!.disableActiveMonitoring).toBe(false);
|
|
1765
|
+
expect(monitorTable[1]!.disableActiveMonitoring).toBe(false);
|
|
1766
|
+
});
|
|
1767
|
+
|
|
1768
|
+
/*
|
|
1769
|
+
* The pause goes through updateBy, not a raw column write, so workflows,
|
|
1770
|
+
* realtime and audit see it exactly as they would an operator's — and the
|
|
1771
|
+
* walk fan-out, which reads this flag, stops feeding the monitor.
|
|
1772
|
+
*/
|
|
1773
|
+
it("writes disableActiveMonitoring through the monitor service", async () => {
|
|
1774
|
+
await NetworkAlertPolicyEngineService.setPolicyMonitorsPaused({
|
|
1775
|
+
projectId: PROJECT_ID,
|
|
1776
|
+
policyId: POLICY_ID,
|
|
1777
|
+
isPaused: true,
|
|
1778
|
+
});
|
|
1779
|
+
|
|
1780
|
+
expect(monitorUpdateByMock).toHaveBeenCalledWith(
|
|
1781
|
+
expect.objectContaining({
|
|
1782
|
+
data: { disableActiveMonitoring: true },
|
|
1783
|
+
props: { isRoot: true },
|
|
1784
|
+
}),
|
|
1785
|
+
);
|
|
1786
|
+
});
|
|
1787
|
+
|
|
1788
|
+
/*
|
|
1789
|
+
* The page is re-read on the flag it is about to write, so a write that
|
|
1790
|
+
* lands on nothing would be read again forever. It stops and says so
|
|
1791
|
+
* instead of spinning the worker.
|
|
1792
|
+
*/
|
|
1793
|
+
it("gives up rather than looping when the write lands on nothing", async () => {
|
|
1794
|
+
monitorUpdateByMock.mockResolvedValue(0);
|
|
1795
|
+
|
|
1796
|
+
await expect(
|
|
1797
|
+
NetworkAlertPolicyEngineService.setPolicyMonitorsPaused({
|
|
1798
|
+
projectId: PROJECT_ID,
|
|
1799
|
+
policyId: POLICY_ID,
|
|
1800
|
+
isPaused: true,
|
|
1801
|
+
}),
|
|
1802
|
+
).resolves.toBe(2);
|
|
1803
|
+
});
|
|
1804
|
+
});
|
|
1805
|
+
|
|
1806
|
+
describe("onMonitorTemplateSynced", () => {
|
|
1807
|
+
it("stamps templateSyncedAt on the policy that provisions from the template", async () => {
|
|
1808
|
+
policyTable = [policy()];
|
|
1809
|
+
|
|
1810
|
+
await NetworkAlertPolicyEngineService.onMonitorTemplateSynced({
|
|
1811
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
1812
|
+
projectId: PROJECT_ID,
|
|
1813
|
+
});
|
|
1814
|
+
|
|
1815
|
+
expect(policyStampMock).toHaveBeenCalledWith(
|
|
1816
|
+
expect.objectContaining({
|
|
1817
|
+
id: POLICY_ID,
|
|
1818
|
+
data: { templateSyncedAt: expect.any(Date) },
|
|
1819
|
+
}),
|
|
1820
|
+
);
|
|
1821
|
+
});
|
|
1822
|
+
|
|
1823
|
+
it("stamps nothing when no policy uses the template", async () => {
|
|
1824
|
+
policyTable = [policy({ monitorTemplateId: OTHER_TEMPLATE_ID })];
|
|
1825
|
+
|
|
1826
|
+
await NetworkAlertPolicyEngineService.onMonitorTemplateSynced({
|
|
1827
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
1828
|
+
projectId: PROJECT_ID,
|
|
1829
|
+
});
|
|
1830
|
+
|
|
1831
|
+
expect(policyStampMock).not.toHaveBeenCalled();
|
|
1832
|
+
});
|
|
1833
|
+
|
|
1834
|
+
/*
|
|
1835
|
+
* Never throws. A bookkeeping column must not fail the template sync the
|
|
1836
|
+
* operator actually asked for.
|
|
1837
|
+
*/
|
|
1838
|
+
it("swallows a stamping failure", async () => {
|
|
1839
|
+
policyTable = [policy()];
|
|
1840
|
+
policyStampMock.mockRejectedValue(new Error("no"));
|
|
1841
|
+
|
|
1842
|
+
await expect(
|
|
1843
|
+
NetworkAlertPolicyEngineService.onMonitorTemplateSynced({
|
|
1844
|
+
monitorTemplateId: TEMPLATE_ID,
|
|
1845
|
+
projectId: PROJECT_ID,
|
|
1846
|
+
}),
|
|
1847
|
+
).resolves.toBeUndefined();
|
|
1848
|
+
});
|
|
1849
|
+
});
|