@oneuptime/common 12.0.22 → 12.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/DetectionRule.ts +55 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/NetworkDevice.ts +44 -0
- package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +584 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +105 -0
- package/Models/DatabaseModels/Project.ts +68 -0
- package/Models/DatabaseModels/User.ts +68 -0
- package/Server/API/TelemetryAPI.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789100000000-AddNetworkDeviceAutoImportRule.ts +60 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789200000000-AddSysObjectIdPatternToAutoImportRule.ts +26 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789300000000-AddAutoApplyVendorHealthTemplate.ts +26 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.ts +28 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Middleware/GzipRequestBody.ts +311 -0
- package/Server/Middleware/MultipartFormData.ts +87 -3
- package/Server/Services/DetectionRuleService.ts +73 -6
- package/Server/Services/Index.ts +207 -0
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +917 -0
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +181 -0
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +59 -0
- package/Server/Services/NetworkDeviceService.ts +148 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
- package/Server/Services/OnCallDutyPolicyFeedService.ts +1 -1
- package/Server/Services/ProjectService.ts +29 -19
- package/Server/Services/SecurityEventService.ts +90 -13
- package/Server/Services/StatusPageResourceService.ts +223 -0
- package/Server/Services/TelemetryAttributeService.ts +17 -0
- package/Server/Services/UserService.ts +4 -6
- package/Server/Types/Markdown.ts +161 -67
- package/Server/Utils/AI/Toolbox/OnCallTools.ts +12 -4
- package/Server/Utils/AnalyticsDatabase/Statement.ts +13 -1
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +297 -6
- package/Server/Utils/Attribution.ts +4 -0
- package/Server/Utils/Marketing/MarketingEventUtil.ts +45 -7
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +39 -1
- package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +55 -3
- package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +21 -0
- package/Server/Utils/StartServer.ts +12 -32
- package/Server/Utils/Telemetry/LlmCostBudgetEvaluator.ts +101 -4
- package/Server/Utils/Telemetry/LlmMetricSpend.ts +130 -0
- package/Server/Views/Partials/AnalyticsConsent.ejs +159 -102
- package/Server/Views/Partials/Head.ejs +2 -1
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +776 -38
- package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +359 -0
- package/Tests/App/Dashboard/CorrelateGraph.test.tsx +865 -0
- package/Tests/App/Dashboard/CorrelationGraph.test.ts +346 -0
- package/Tests/App/Dashboard/CriteriaFilterConditionDropdown.test.tsx +256 -0
- package/Tests/App/Dashboard/CriteriaFilterDefaults.test.ts +738 -0
- package/Tests/App/Dashboard/CriteriaFilterMonitorTypeChange.test.ts +1122 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +283 -0
- package/Tests/App/Dashboard/ExternalStatusPageCriteriaFilter.test.ts +407 -0
- package/Tests/App/Dashboard/MetricSeriesInvestigateMenu.test.tsx +5 -14
- package/Tests/App/Dashboard/MonitorCriteriaActionToggles.test.tsx +426 -0
- package/Tests/App/Dashboard/MonitorStepsCriteriaAlignmentWiring.test.tsx +352 -0
- package/Tests/App/Dashboard/OnCallLayerCardOverrides.test.tsx +278 -0
- package/Tests/App/Dashboard/OnCallLayerShiftPreviewOverrides.test.ts +237 -0
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +2 -2
- package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +460 -0
- package/Tests/App/Dashboard/SecurityEventAttributeUtil.test.ts +171 -0
- package/Tests/App/Dashboard/SecurityEventCorrelation.test.ts +857 -0
- package/Tests/App/Dashboard/SecurityEventDetailObservables.test.tsx +194 -0
- package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +124 -0
- package/Tests/App/Dashboard/SecurityEventsMonitorStepForm.test.tsx +79 -19
- package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +382 -0
- package/Tests/App/StatusPage/BulkAddStatusPageMonitors.test.ts +216 -0
- package/Tests/App/StatusPage/BulkAddStatusPageMonitorsModal.test.tsx +590 -11
- package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +757 -0
- package/Tests/Models/DiscoveryScanNameColumn.test.ts +293 -0
- package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +564 -0
- package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +120 -4
- package/Tests/Server/Middleware/GzipRequestBody.test.ts +725 -0
- package/Tests/Server/Middleware/MultipartFormData.test.ts +298 -0
- package/Tests/Server/Services/AddDetectionRuleDistinctCountColumnsMigration.test.ts +311 -0
- package/Tests/Server/Services/AutoImportScanCredentialSelect.test.ts +205 -0
- package/Tests/Server/Services/DetectionRuleService.test.ts +134 -2
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +7 -1
- package/Tests/Server/Services/FeedRetentionConsistency.test.ts +131 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +933 -0
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +194 -0
- package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +800 -0
- package/Tests/Server/Services/OnCallScheduleAttachRosterRefresh.test.ts +244 -0
- package/Tests/Server/Services/SecurityEventService.test.ts +376 -0
- package/Tests/Server/Services/StatusPageResourceDuplicates.test.ts +703 -0
- package/Tests/Server/Services/TelemetryAttributeServiceSecurityEvent.test.ts +256 -0
- package/Tests/Server/Types/Workflow/Components/ComponentRegistryParity.test.ts +417 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorWhereOperators.test.ts +677 -0
- package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +43 -0
- package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +15 -11
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +97 -1
- package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +369 -8
- package/Tests/Server/Utils/SecurityEvent/SigmaClickhouseCompiler.test.ts +35 -0
- package/Tests/Server/Utils/Telemetry/LlmCostBudgetEvaluator.test.ts +368 -4
- package/Tests/Server/Utils/Telemetry/LlmMetricSpend.test.ts +245 -0
- package/Tests/Server/Views/AnalyticsConsentPartial.test.ts +48 -5
- package/Tests/Types/Code/YamlSyntax.test.ts +396 -0
- package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +957 -0
- package/Tests/Types/Monitor/MonitorCriteriaActionValidation.test.ts +598 -0
- package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +49 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +6 -6
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +4 -4
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +4 -3
- package/Tests/Types/Telemetry/LlmMetricConventions.test.ts +193 -0
- package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +0 -12
- package/Tests/UI/Components/CardModelDetailEdit.test.tsx +1 -17
- package/Tests/UI/Components/CodeEditor.test.tsx +474 -10
- package/Tests/UI/Components/Detail/YamlField.test.tsx +105 -0
- package/Tests/UI/Components/EntityDropdownLabelsBulkAdd.test.tsx +319 -0
- package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +231 -0
- package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +1 -0
- package/Tests/UI/Components/Forms/ValidationYAML.test.ts +234 -0
- package/Tests/UI/Components/ModelTable/AttributeColumns.test.tsx +573 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableAttributeColumns.test.tsx +824 -0
- package/Tests/UI/Components/ModelTable/ColumnCustomizationModalAddableColumns.test.tsx +707 -0
- package/Tests/UI/Components/SideOver.test.tsx +1 -1
- package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +294 -0
- package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +436 -0
- package/Tests/UI/Components/TableBulkCsvExport.test.tsx +6 -2
- package/Tests/UI/Components/Toggle.test.tsx +25 -0
- package/Tests/UI/Components/YamlEditor.test.tsx +847 -0
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +252 -0
- package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +516 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +272 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +221 -0
- package/Tests/Utils/NetworkDiscovery/ScanNameUtil.test.ts +312 -0
- package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +164 -0
- package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +468 -0
- package/Tests/Utils/Telemetry/LlmMetricQuery.test.ts +472 -0
- package/Types/Code/YamlSyntax.ts +396 -0
- package/Types/Exception/ExceptionCode.ts +1 -0
- package/Types/Exception/PayloadTooLargeException.ts +8 -0
- package/Types/Marketing/Attribution.ts +10 -0
- package/Types/Marketing/MarketingEvent.ts +4 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +116 -56
- package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +2 -1
- package/Types/NetworkAutomation/RuleRunResult.ts +84 -0
- package/Types/Permission.ts +47 -0
- package/Types/SecurityEvent/DetectionFindingConstants.ts +11 -0
- package/Types/Telemetry/LlmMetricConventions.ts +124 -0
- package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +3 -0
- package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +10 -1
- package/UI/Components/CodeEditor/CodeEditor.tsx +241 -79
- package/UI/Components/CodeEditor/YamlEditor.tsx +369 -0
- package/UI/Components/Detail/Detail.tsx +10 -0
- package/UI/Components/EntityDropdown/EntityDropdown.tsx +33 -0
- package/UI/Components/Forms/Fields/FormField.tsx +31 -0
- package/UI/Components/Forms/Types/Field.ts +8 -0
- package/UI/Components/Forms/Types/FormFieldSchemaType.ts +1 -0
- package/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.ts +2 -0
- package/UI/Components/Forms/Validation.ts +46 -0
- package/UI/Components/Input/Input.tsx +3 -0
- package/UI/Components/ModelTable/AttributeColumns.tsx +321 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +263 -14
- package/UI/Components/ModelTable/Column.ts +8 -0
- package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +310 -0
- package/UI/Components/ModelTable/ColumnPreference.ts +13 -1
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.tsx +2 -2
- package/UI/Components/SideOver/SideOver.tsx +5 -5
- package/UI/Components/StatusPage/ResourceGrid.tsx +82 -2
- package/UI/Components/StatusPage/ResourceList.tsx +197 -38
- package/UI/Components/Toggle/Toggle.tsx +9 -1
- package/UI/Components/Types/FieldType.ts +1 -0
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +73 -1
- package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +257 -0
- package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +183 -0
- package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +95 -0
- package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +66 -0
- package/Utils/NetworkDiscovery/ScanNameUtil.ts +181 -0
- package/Utils/NetworkDiscovery/ScanTargetUtil.ts +82 -0
- package/Utils/StatusPage/ResourceExplorer.ts +258 -0
- package/Utils/Telemetry/LlmMetricQuery.ts +204 -0
- package/build/dist/Models/DatabaseModels/DetectionRule.js +57 -0
- package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +609 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +97 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +76 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +76 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +17 -0
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789100000000-AddNetworkDeviceAutoImportRule.js +35 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789100000000-AddNetworkDeviceAutoImportRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789200000000-AddSysObjectIdPatternToAutoImportRule.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789200000000-AddSysObjectIdPatternToAutoImportRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789300000000-AddAutoApplyVendorHealthTemplate.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789300000000-AddAutoApplyVendorHealthTemplate.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js +21 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js +42 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/GzipRequestBody.js +224 -0
- package/build/dist/Server/Middleware/GzipRequestBody.js.map +1 -0
- package/build/dist/Server/Middleware/MultipartFormData.js +71 -2
- package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
- package/build/dist/Server/Services/DetectionRuleService.js +49 -4
- package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +206 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +711 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +155 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +50 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +124 -0
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +68 -13
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +25 -45
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/SecurityEventService.js +57 -5
- package/build/dist/Server/Services/SecurityEventService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageResourceService.js +140 -0
- package/build/dist/Server/Services/StatusPageResourceService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryAttributeService.js +17 -0
- package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +2 -12
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +147 -61
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +12 -4
- package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +12 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +246 -9
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/Attribution.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +27 -7
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +26 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +42 -7
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +18 -0
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +12 -21
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js +76 -5
- package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js +102 -0
- package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js.map +1 -0
- package/build/dist/Types/Code/YamlSyntax.js +212 -0
- package/build/dist/Types/Code/YamlSyntax.js.map +1 -0
- package/build/dist/Types/Exception/ExceptionCode.js +1 -0
- package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
- package/build/dist/Types/Exception/PayloadTooLargeException.js +8 -0
- package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -0
- package/build/dist/Types/Marketing/Attribution.js +10 -0
- package/build/dist/Types/Marketing/Attribution.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +112 -51
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +2 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js +24 -0
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -1
- package/build/dist/Types/Permission.js +41 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +9 -0
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
- package/build/dist/Types/Telemetry/LlmMetricConventions.js +98 -0
- package/build/dist/Types/Telemetry/LlmMetricConventions.js.map +1 -0
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +5 -2
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +206 -76
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/YamlEditor.js +201 -0
- package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -0
- package/build/dist/UI/Components/Detail/Detail.js +9 -0
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +16 -1
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +14 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Forms/Types/Field.js.map +1 -1
- package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js +1 -0
- package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js.map +1 -1
- package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js +2 -0
- package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js.map +1 -1
- package/build/dist/UI/Components/Forms/Validation.js +27 -0
- package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +1 -1
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/AttributeColumns.js +159 -0
- package/build/dist/UI/Components/ModelTable/AttributeColumns.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +179 -17
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +133 -2
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ColumnPreference.js +7 -1
- package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.js +2 -2
- package/build/dist/UI/Components/SideOver/SideOver.js +5 -5
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js +28 -2
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceList.js +87 -20
- package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
- package/build/dist/UI/Components/Toggle/Toggle.js +9 -1
- package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
- package/build/dist/UI/Components/Types/FieldType.js +1 -0
- package/build/dist/UI/Components/Types/FieldType.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +37 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +149 -0
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +121 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +75 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +59 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js +120 -0
- package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +60 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -1
- package/build/dist/Utils/StatusPage/ResourceExplorer.js +171 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -1
- package/build/dist/Utils/Telemetry/LlmMetricQuery.js +119 -0
- package/build/dist/Utils/Telemetry/LlmMetricQuery.js.map +1 -0
- package/jest.config.json +2 -0
- package/package.json +1 -1
- package/tsconfig.json +2 -1
- package/Tests/UI/Components/Toast.test.tsx +0 -197
- package/Tests/UI/Components/ToastStacking.test.tsx +0 -198
- package/UI/Components/Toast/Toast.tsx +0 -189
- package/UI/Components/Toast/ToastInit.tsx +0 -110
- package/build/dist/UI/Components/Toast/Toast.js +0 -123
- package/build/dist/UI/Components/Toast/Toast.js.map +0 -1
- package/build/dist/UI/Components/Toast/ToastInit.js +0 -53
- package/build/dist/UI/Components/Toast/ToastInit.js.map +0 -1
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import Model from "../../Models/DatabaseModels/NetworkDeviceAutoImportRule";
|
|
3
|
+
import { OnCreate, OnUpdate } from "../Types/Database/Hooks";
|
|
4
|
+
import CreateBy from "../Types/Database/CreateBy";
|
|
5
|
+
import UpdateBy from "../Types/Database/UpdateBy";
|
|
6
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
7
|
+
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
8
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
9
|
+
import RulePatternMatchUtil from "../../Utils/Rules/RulePatternMatchUtil";
|
|
10
|
+
import ScanTargetUtil from "../../Utils/NetworkDiscovery/ScanTargetUtil";
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* Write-time validation for auto-import rules, following the
|
|
14
|
+
* NetworkSiteAssignmentRuleService contract: a condition that can only ever
|
|
15
|
+
* match nothing is rejected where the user can see it, not logged about by
|
|
16
|
+
* the engine long after they left the form.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/*
|
|
20
|
+
* What a sysObjectID condition may contain: an optional leading dot, then
|
|
21
|
+
* digits, dots and '*' wildcards. Hoisted so the literal is not the object
|
|
22
|
+
* of a member expression, which `wrap-regex` and Prettier cannot agree on —
|
|
23
|
+
* same reason as CidrMatchUtil.
|
|
24
|
+
*/
|
|
25
|
+
const OID_PATTERN_SHAPE: RegExp = /^\.?[\d.*]+$/;
|
|
26
|
+
export class Service extends DatabaseService<Model> {
|
|
27
|
+
public constructor() {
|
|
28
|
+
super(Model);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@CaptureSpan()
|
|
32
|
+
protected override async onBeforeCreate(
|
|
33
|
+
createBy: CreateBy<Model>,
|
|
34
|
+
): Promise<OnCreate<Model>> {
|
|
35
|
+
this.validateCriteria({
|
|
36
|
+
ipMatchTarget: createBy.data.ipMatchTarget,
|
|
37
|
+
sysNamePattern: createBy.data.sysNamePattern,
|
|
38
|
+
sysDescrPattern: createBy.data.sysDescrPattern,
|
|
39
|
+
sysObjectIdPattern: createBy.data.sysObjectIdPattern,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return { createBy, carryForward: null };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@CaptureSpan()
|
|
46
|
+
protected override async onBeforeUpdate(
|
|
47
|
+
updateBy: UpdateBy<Model>,
|
|
48
|
+
): Promise<OnUpdate<Model>> {
|
|
49
|
+
const dataKeys: Array<string> = Object.keys(updateBy.data || {});
|
|
50
|
+
|
|
51
|
+
const isCriteriaChange: boolean =
|
|
52
|
+
dataKeys.includes("ipMatchTarget") ||
|
|
53
|
+
dataKeys.includes("sysNamePattern") ||
|
|
54
|
+
dataKeys.includes("sysDescrPattern") ||
|
|
55
|
+
dataKeys.includes("sysObjectIdPattern");
|
|
56
|
+
|
|
57
|
+
if (!isCriteriaChange) {
|
|
58
|
+
return { updateBy, carryForward: null };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/*
|
|
62
|
+
* The update may clear one criterion while another only exists on the
|
|
63
|
+
* stored row, so validate the RESULTING state of every matched row.
|
|
64
|
+
*/
|
|
65
|
+
const existingRules: Array<Model> = await this.findBy({
|
|
66
|
+
query: updateBy.query,
|
|
67
|
+
select: {
|
|
68
|
+
_id: true,
|
|
69
|
+
ipMatchTarget: true,
|
|
70
|
+
sysNamePattern: true,
|
|
71
|
+
sysDescrPattern: true,
|
|
72
|
+
sysObjectIdPattern: true,
|
|
73
|
+
},
|
|
74
|
+
limit: LIMIT_MAX,
|
|
75
|
+
skip: 0,
|
|
76
|
+
props: {
|
|
77
|
+
isRoot: true,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const data: Record<string, unknown> = updateBy.data as unknown as Record<
|
|
82
|
+
string,
|
|
83
|
+
unknown
|
|
84
|
+
>;
|
|
85
|
+
|
|
86
|
+
for (const existingRule of existingRules) {
|
|
87
|
+
this.validateCriteria({
|
|
88
|
+
ipMatchTarget: dataKeys.includes("ipMatchTarget")
|
|
89
|
+
? (data["ipMatchTarget"] as string | null)
|
|
90
|
+
: existingRule.ipMatchTarget,
|
|
91
|
+
sysNamePattern: dataKeys.includes("sysNamePattern")
|
|
92
|
+
? (data["sysNamePattern"] as string | null)
|
|
93
|
+
: existingRule.sysNamePattern,
|
|
94
|
+
sysDescrPattern: dataKeys.includes("sysDescrPattern")
|
|
95
|
+
? (data["sysDescrPattern"] as string | null)
|
|
96
|
+
: existingRule.sysDescrPattern,
|
|
97
|
+
sysObjectIdPattern: dataKeys.includes("sysObjectIdPattern")
|
|
98
|
+
? (data["sysObjectIdPattern"] as string | null)
|
|
99
|
+
: existingRule.sysObjectIdPattern,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return { updateBy, carryForward: null };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private validateCriteria(data: {
|
|
107
|
+
ipMatchTarget?: string | null | undefined;
|
|
108
|
+
sysNamePattern?: string | null | undefined;
|
|
109
|
+
sysDescrPattern?: string | null | undefined;
|
|
110
|
+
sysObjectIdPattern?: string | null | undefined;
|
|
111
|
+
}): void {
|
|
112
|
+
const ipMatchTarget: string = (data.ipMatchTarget || "").trim();
|
|
113
|
+
const sysNamePattern: string = (data.sysNamePattern || "").trim();
|
|
114
|
+
const sysDescrPattern: string = (data.sysDescrPattern || "").trim();
|
|
115
|
+
const sysObjectIdPattern: string = (data.sysObjectIdPattern || "").trim();
|
|
116
|
+
|
|
117
|
+
/*
|
|
118
|
+
* A rule with no conditions matches nothing (see AutoImportRuleMatcher) —
|
|
119
|
+
* and would read as "match everything" to whoever finds it later.
|
|
120
|
+
*/
|
|
121
|
+
if (
|
|
122
|
+
!ipMatchTarget &&
|
|
123
|
+
!sysNamePattern &&
|
|
124
|
+
!sysDescrPattern &&
|
|
125
|
+
!sysObjectIdPattern
|
|
126
|
+
) {
|
|
127
|
+
throw new BadDataException(
|
|
128
|
+
"At least one of Host IP Is In, System Name Pattern, System Description Pattern, or System Object ID Pattern is required.",
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/*
|
|
133
|
+
* Well-formedness only, deliberately NOT the scan-size ceiling: matching
|
|
134
|
+
* an address against 10.0.0.0/8 is a containment check, not a sweep, so
|
|
135
|
+
* a condition covering a huge block is legitimate here even though a
|
|
136
|
+
* scan target that size is not.
|
|
137
|
+
*/
|
|
138
|
+
if (ipMatchTarget && !ScanTargetUtil.isValid(ipMatchTarget)) {
|
|
139
|
+
throw new BadDataException(
|
|
140
|
+
`"${ipMatchTarget}" is not a valid Host IP condition. ${ScanTargetUtil.getSyntaxHint()}`,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
this.validatePattern("System Name Pattern", sysNamePattern);
|
|
145
|
+
this.validatePattern("System Description Pattern", sysDescrPattern);
|
|
146
|
+
this.validateOidPattern(sysObjectIdPattern);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private validatePattern(title: string, pattern: string): void {
|
|
150
|
+
if (!pattern || RulePatternMatchUtil.isSupportedPattern(pattern)) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
throw new BadDataException(
|
|
155
|
+
`${title} is neither a valid regular expression nor a '*' wildcard pattern, so it would never match: ${pattern}`,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/*
|
|
160
|
+
* The sysObjectID condition is NOT free-text: an OID is a dotted numeric
|
|
161
|
+
* arc, matched as a literal-dot '*' glob or an arc prefix (see
|
|
162
|
+
* AutoImportRuleMatcher.matchesOidPattern — regex-first matching would make
|
|
163
|
+
* "1.3.6.1.4.1.9.*" match enterprise 94 too). So the only characters that
|
|
164
|
+
* can ever match anything are digits, dots and '*'; anything else is a
|
|
165
|
+
* pattern that silently never fires, which is exactly what this service
|
|
166
|
+
* exists to reject at the write.
|
|
167
|
+
*/
|
|
168
|
+
private validateOidPattern(pattern: string): void {
|
|
169
|
+
if (!pattern) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!OID_PATTERN_SHAPE.test(pattern)) {
|
|
174
|
+
throw new BadDataException(
|
|
175
|
+
`System Object ID Pattern must be an OID prefix (1.3.6.1.4.1.9) or a '*' wildcard OID pattern (1.3.6.1.4.1.9.*) — digits, dots and '*' only: ${pattern}`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export default new Service();
|
|
@@ -6,6 +6,7 @@ import UpdateBy from "../Types/Database/UpdateBy";
|
|
|
6
6
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
7
7
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
8
8
|
import ScanTargetUtil from "../../Utils/NetworkDiscovery/ScanTargetUtil";
|
|
9
|
+
import ScanNameUtil from "../../Utils/NetworkDiscovery/ScanNameUtil";
|
|
9
10
|
|
|
10
11
|
export class Service extends DatabaseService<Model> {
|
|
11
12
|
public constructor() {
|
|
@@ -33,6 +34,25 @@ export class Service extends DatabaseService<Model> {
|
|
|
33
34
|
): Promise<OnCreate<Model>> {
|
|
34
35
|
this.validateScanTarget(createBy.data.cidr);
|
|
35
36
|
|
|
37
|
+
/*
|
|
38
|
+
* The name is normalized as well as validated — collapsed onto one line,
|
|
39
|
+
* trimmed, and a blank one dropped entirely — so the column holds either a
|
|
40
|
+
* name or nothing. An empty string stored here would read as a name to
|
|
41
|
+
* every `scan.name ?` in the product and render as a blank line above the
|
|
42
|
+
* scan target. See ScanNameUtil.
|
|
43
|
+
*/
|
|
44
|
+
this.validateScanName(createBy.data.name);
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
* Written through a cast because `exactOptionalPropertyTypes` forbids
|
|
48
|
+
* assigning `undefined` to an optional property — and dropping a blank
|
|
49
|
+
* name is exactly that assignment. Undefined rather than null: a model
|
|
50
|
+
* instance starts with every column undefined, so this leaves the row in
|
|
51
|
+
* the state a scan created without a name would already have been in.
|
|
52
|
+
*/
|
|
53
|
+
(createBy.data as unknown as Record<string, unknown>)["name"] =
|
|
54
|
+
ScanNameUtil.normalize(createBy.data.name) ?? undefined;
|
|
55
|
+
|
|
36
56
|
return { createBy, carryForward: null };
|
|
37
57
|
}
|
|
38
58
|
|
|
@@ -54,6 +74,27 @@ export class Service extends DatabaseService<Model> {
|
|
|
54
74
|
);
|
|
55
75
|
}
|
|
56
76
|
|
|
77
|
+
/*
|
|
78
|
+
* The name IS user-updatable — renaming a scan is the whole point of
|
|
79
|
+
* letting it be named — so this path is the one the form actually takes,
|
|
80
|
+
* not just a guard against root writers.
|
|
81
|
+
*
|
|
82
|
+
* Cleared with null rather than left as "": the form sends back an empty
|
|
83
|
+
* box as an empty string, and the operator who emptied it meant "this scan
|
|
84
|
+
* has no name", which is what NULL says. `undefined` would not do — the
|
|
85
|
+
* key is present in the update, and an undefined value is a column TypeORM
|
|
86
|
+
* would try to write.
|
|
87
|
+
*/
|
|
88
|
+
if (dataKeys.includes("name")) {
|
|
89
|
+
const data: Record<string, unknown> = updateBy.data as Record<
|
|
90
|
+
string,
|
|
91
|
+
unknown
|
|
92
|
+
>;
|
|
93
|
+
|
|
94
|
+
this.validateScanName(data["name"]);
|
|
95
|
+
data["name"] = ScanNameUtil.normalize(data["name"]);
|
|
96
|
+
}
|
|
97
|
+
|
|
57
98
|
return { updateBy, carryForward: null };
|
|
58
99
|
}
|
|
59
100
|
|
|
@@ -75,6 +116,24 @@ export class Service extends DatabaseService<Model> {
|
|
|
75
116
|
throw new BadDataException(validationError);
|
|
76
117
|
}
|
|
77
118
|
}
|
|
119
|
+
|
|
120
|
+
/*
|
|
121
|
+
* Same contract as validateScanTarget above: the value is passed through
|
|
122
|
+
* untouched, because it arrives straight from the request JSON and may be a
|
|
123
|
+
* number, an object or an array rather than a string. ScanNameUtil type-
|
|
124
|
+
* guards internally and reports a non-string as such.
|
|
125
|
+
*
|
|
126
|
+
* An ABSENT or blank name is not an error — the column is optional, and a
|
|
127
|
+
* scan with no name reads as it always did, by its target.
|
|
128
|
+
*/
|
|
129
|
+
private validateScanName(name: unknown): void {
|
|
130
|
+
const validationError: string | null =
|
|
131
|
+
ScanNameUtil.getValidationError(name);
|
|
132
|
+
|
|
133
|
+
if (validationError) {
|
|
134
|
+
throw new BadDataException(validationError);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
78
137
|
}
|
|
79
138
|
|
|
80
139
|
export default new Service();
|
|
@@ -303,6 +303,24 @@ export class Service extends DatabaseService<Model> {
|
|
|
303
303
|
await this.applySiteAssignmentRulesToDevice(createdItem.id!);
|
|
304
304
|
}
|
|
305
305
|
})
|
|
306
|
+
.then(async () => {
|
|
307
|
+
/*
|
|
308
|
+
* A device created monitor-backed adopts its monitor's CURRENT
|
|
309
|
+
* status right away rather than waiting for that monitor's next
|
|
310
|
+
* status CHANGE. Skipped for SNMP devices, which are judged by
|
|
311
|
+
* their own walk.
|
|
312
|
+
*/
|
|
313
|
+
if (
|
|
314
|
+
NetworkDeviceMonitoringMethodUtil.isMonitorBacked(
|
|
315
|
+
createdItem.monitoringMethod,
|
|
316
|
+
)
|
|
317
|
+
) {
|
|
318
|
+
await this.refreshStampedMonitorStatus({
|
|
319
|
+
deviceId: createdItem.id!,
|
|
320
|
+
clearWhenNotMonitorBacked: false,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
})
|
|
306
324
|
.catch((error: Error) => {
|
|
307
325
|
logger.error(
|
|
308
326
|
`Error applying network device rules in NetworkDeviceService.onCreateSuccess: ${error}`,
|
|
@@ -453,6 +471,109 @@ export class Service extends DatabaseService<Model> {
|
|
|
453
471
|
};
|
|
454
472
|
}
|
|
455
473
|
|
|
474
|
+
/*
|
|
475
|
+
* Re-derives one device's stamped `currentMonitorStatusId` from its
|
|
476
|
+
* binding, and refreshes its site chain if the stamp moved.
|
|
477
|
+
*
|
|
478
|
+
* The stamp is what every monitor-backed surface reads — the device list
|
|
479
|
+
* pill, the site rollup, the topology node — and until this existed the
|
|
480
|
+
* ONLY thing that ever wrote it was
|
|
481
|
+
* `NetworkSiteService.onMonitorStatusChanged`, which fires on a monitor's
|
|
482
|
+
* next status CHANGE. Bind a device to a Ping monitor that is already Up
|
|
483
|
+
* and staying Up and nothing writes the stamp at all, so the device sits
|
|
484
|
+
* on "Pending" until the monitor happens to go down — which is
|
|
485
|
+
* OneUptime/oneuptime#3392. Binding is itself an event that decides the
|
|
486
|
+
* device's status, so it stamps here.
|
|
487
|
+
*
|
|
488
|
+
* `clearWhenNotMonitorBacked` is for the write that moves a device OFF
|
|
489
|
+
* monitor-backed: the ping monitor's verdict must not outlive the binding
|
|
490
|
+
* (DeviceHealthStateUtil lets a stamped status beat reachability, so a
|
|
491
|
+
* stale one would poison the site rollup of a device that is now walked).
|
|
492
|
+
* It is deliberately NOT set when a write only touches the monitor
|
|
493
|
+
* binding of an SNMP device, because an SNMP device's stamp comes from
|
|
494
|
+
* the Network Device monitor that watches it, and that binding lives in
|
|
495
|
+
* the monitor's step data rather than in this column.
|
|
496
|
+
*/
|
|
497
|
+
@CaptureSpan()
|
|
498
|
+
public async refreshStampedMonitorStatus(data: {
|
|
499
|
+
deviceId: ObjectID;
|
|
500
|
+
clearWhenNotMonitorBacked: boolean;
|
|
501
|
+
}): Promise<void> {
|
|
502
|
+
const device: Model | null = await this.findOneById({
|
|
503
|
+
id: data.deviceId,
|
|
504
|
+
select: {
|
|
505
|
+
_id: true,
|
|
506
|
+
projectId: true,
|
|
507
|
+
siteId: true,
|
|
508
|
+
monitoringMethod: true,
|
|
509
|
+
monitorId: true,
|
|
510
|
+
currentMonitorStatusId: true,
|
|
511
|
+
},
|
|
512
|
+
props: {
|
|
513
|
+
isRoot: true,
|
|
514
|
+
},
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
if (!device || !device.projectId) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const isMonitorBacked: boolean =
|
|
522
|
+
NetworkDeviceMonitoringMethodUtil.isMonitorBacked(
|
|
523
|
+
device.monitoringMethod,
|
|
524
|
+
);
|
|
525
|
+
|
|
526
|
+
if (!isMonitorBacked && !data.clearWhenNotMonitorBacked) {
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
let monitorStatusId: ObjectID | null = null;
|
|
531
|
+
|
|
532
|
+
if (isMonitorBacked && device.monitorId) {
|
|
533
|
+
/*
|
|
534
|
+
* Scoped to the device's project on the read as well as on the write
|
|
535
|
+
* path in onBeforeCreate/onBeforeUpdate: a monitor from another
|
|
536
|
+
* tenant must never be able to stamp a status here.
|
|
537
|
+
*/
|
|
538
|
+
const monitor: Monitor | null = await MonitorService.findOneBy({
|
|
539
|
+
query: {
|
|
540
|
+
_id: device.monitorId,
|
|
541
|
+
projectId: device.projectId,
|
|
542
|
+
},
|
|
543
|
+
select: {
|
|
544
|
+
_id: true,
|
|
545
|
+
currentMonitorStatusId: true,
|
|
546
|
+
},
|
|
547
|
+
props: {
|
|
548
|
+
isRoot: true,
|
|
549
|
+
},
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
monitorStatusId = monitor?.currentMonitorStatusId || null;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const currentStampId: string | null =
|
|
556
|
+
device.currentMonitorStatusId?.toString() || null;
|
|
557
|
+
const nextStampId: string | null = monitorStatusId?.toString() || null;
|
|
558
|
+
|
|
559
|
+
if (currentStampId === nextStampId) {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
await this.updateColumnsByIdWithoutHooks({
|
|
564
|
+
id: data.deviceId,
|
|
565
|
+
data: {
|
|
566
|
+
currentMonitorStatusId: monitorStatusId,
|
|
567
|
+
},
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
if (device.siteId) {
|
|
571
|
+
await NetworkSiteService.recomputeRollupForSiteAndAncestors(
|
|
572
|
+
device.siteId,
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
456
577
|
/*
|
|
457
578
|
* Site maintenance after device updates. Resilient by design: a rollup
|
|
458
579
|
* or rule-engine failure must never fail the device update itself.
|
|
@@ -462,6 +583,33 @@ export class Service extends DatabaseService<Model> {
|
|
|
462
583
|
onUpdate: OnUpdate<Model>,
|
|
463
584
|
updatedItemIds: Array<ObjectID>,
|
|
464
585
|
): Promise<OnUpdate<Model>> {
|
|
586
|
+
/*
|
|
587
|
+
* Re-stamp before the site maintenance below, and in its own try: the
|
|
588
|
+
* two are independent, and a rollup failure must not cost the device
|
|
589
|
+
* its status (nor the other way round).
|
|
590
|
+
*/
|
|
591
|
+
try {
|
|
592
|
+
const dataKeys: Array<string> = Object.keys(onUpdate.updateBy.data || {});
|
|
593
|
+
const isMethodWrite: boolean = dataKeys.includes("monitoringMethod");
|
|
594
|
+
const isMonitorWrite: boolean = RelationIdUtil.isWritten(
|
|
595
|
+
dataKeys,
|
|
596
|
+
MONITOR_KEYS,
|
|
597
|
+
);
|
|
598
|
+
|
|
599
|
+
if (isMethodWrite || isMonitorWrite) {
|
|
600
|
+
for (const deviceId of updatedItemIds) {
|
|
601
|
+
await this.refreshStampedMonitorStatus({
|
|
602
|
+
deviceId: deviceId,
|
|
603
|
+
clearWhenNotMonitorBacked: isMethodWrite,
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
} catch (error) {
|
|
608
|
+
logger.error(
|
|
609
|
+
`Error in NetworkDeviceService.onUpdateSuccess monitor status refresh: ${error}`,
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
|
|
465
613
|
try {
|
|
466
614
|
const dataKeys: Array<string> = Object.keys(onUpdate.updateBy.data || {});
|
|
467
615
|
|
|
@@ -31,6 +31,48 @@ export class Service extends DatabaseService<Model> {
|
|
|
31
31
|
super(Model);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Re-resolve and persist the schedule's roster after it is attached to, or
|
|
36
|
+
* detached from, an on-call policy.
|
|
37
|
+
*
|
|
38
|
+
* The persisted roster columns are derived state, and one of their inputs is
|
|
39
|
+
* WHICH policies escalate to the schedule: a schedule attached to exactly one
|
|
40
|
+
* policy is resolved in that policy's context, so its policy-scoped user
|
|
41
|
+
* overrides count, and a schedule attached to none or to several is resolved
|
|
42
|
+
* policy-blind (OnCallDutyPolicyScheduleService.getSingleAttachedPolicyId).
|
|
43
|
+
* Attaching or detaching therefore changes the correct answer, and every other
|
|
44
|
+
* input — layers, layer users, overrides — already refreshes on change.
|
|
45
|
+
*
|
|
46
|
+
* Without this the roster stayed on the pre-attach answer until the next
|
|
47
|
+
* natural hand-off, so the schedule page's "X is currently on the roster"
|
|
48
|
+
* banner and the "On Call Now" column named the originally-scheduled user for
|
|
49
|
+
* the whole override window while alert routing paged the substitute.
|
|
50
|
+
* https://github.com/OneUptime/oneuptime/issues/3411
|
|
51
|
+
*
|
|
52
|
+
* Best-effort: an attach must not fail because a roster could not be
|
|
53
|
+
* recomputed, and the refresh is idempotent (an unaffected schedule simply
|
|
54
|
+
* resolves to the same roster and diffs to "no change", so no duplicate
|
|
55
|
+
* hand-off notification is sent).
|
|
56
|
+
*/
|
|
57
|
+
private async refreshScheduleRoster(
|
|
58
|
+
onCallDutyPolicyScheduleId: ObjectID | null | undefined,
|
|
59
|
+
): Promise<void> {
|
|
60
|
+
if (!onCallDutyPolicyScheduleId) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
await OnCallDutyPolicyScheduleService.refreshCurrentUserIdAndHandoffTimeInSchedule(
|
|
66
|
+
onCallDutyPolicyScheduleId,
|
|
67
|
+
);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
logger.error(
|
|
70
|
+
"Error refreshing the roster after an on-call schedule was attached to or detached from a policy (best-effort).",
|
|
71
|
+
);
|
|
72
|
+
logger.error(err);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
34
76
|
protected override async onCreateSuccess(
|
|
35
77
|
_onCreate: OnCreate<Model>,
|
|
36
78
|
createdItem: Model,
|
|
@@ -75,6 +117,12 @@ export class Service extends DatabaseService<Model> {
|
|
|
75
117
|
);
|
|
76
118
|
}
|
|
77
119
|
|
|
120
|
+
/*
|
|
121
|
+
* Bring the persisted roster in line with the new policy attachment before
|
|
122
|
+
* anything below can return early. See refreshScheduleRoster.
|
|
123
|
+
*/
|
|
124
|
+
await this.refreshScheduleRoster(createdModel.onCallDutyPolicyScheduleId);
|
|
125
|
+
|
|
78
126
|
// send notification to the new current user.
|
|
79
127
|
|
|
80
128
|
const userOnSchedule: ObjectID | null =
|
|
@@ -324,6 +372,23 @@ export class Service extends DatabaseService<Model> {
|
|
|
324
372
|
): Promise<OnDelete<Model>> {
|
|
325
373
|
const deletedItems: Array<Model> = onDelete.carryForward.deletedItems;
|
|
326
374
|
|
|
375
|
+
/*
|
|
376
|
+
* Detaching changes the schedule's policy context just as attaching does, so
|
|
377
|
+
* its roster has to be re-resolved here too. Deduped by schedule: removing a
|
|
378
|
+
* schedule from several escalation rules of one policy is one context
|
|
379
|
+
* change, not several. See refreshScheduleRoster.
|
|
380
|
+
*/
|
|
381
|
+
const refreshedScheduleIds: Set<string> = new Set<string>();
|
|
382
|
+
for (const deletedItem of deletedItems) {
|
|
383
|
+
const scheduleId: string | undefined =
|
|
384
|
+
deletedItem.onCallDutyPolicyScheduleId?.toString();
|
|
385
|
+
if (!scheduleId || refreshedScheduleIds.has(scheduleId)) {
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
refreshedScheduleIds.add(scheduleId);
|
|
389
|
+
await this.refreshScheduleRoster(deletedItem.onCallDutyPolicyScheduleId);
|
|
390
|
+
}
|
|
391
|
+
|
|
327
392
|
for (const deletedItem of deletedItems) {
|
|
328
393
|
const userOnSchedule: ObjectID | null =
|
|
329
394
|
await OnCallDutyPolicyScheduleService.getCurrentUserIdInSchedule(
|
|
@@ -19,7 +19,7 @@ export class Service extends DatabaseService<OnCallDutyPolicyFeed> {
|
|
|
19
19
|
super(OnCallDutyPolicyFeed);
|
|
20
20
|
|
|
21
21
|
if (IsBillingEnabled) {
|
|
22
|
-
this.hardDeleteItemsOlderThanInDays("createdAt",
|
|
22
|
+
this.hardDeleteItemsOlderThanInDays("createdAt", 3 * 365); // 3 years
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -16,8 +16,14 @@ import UpdateBy from "../Types/Database/UpdateBy";
|
|
|
16
16
|
import logger, { LogAttributes } from "../Utils/Logger";
|
|
17
17
|
import Errors from "../Utils/Errors";
|
|
18
18
|
import ProductAnalytics from "../Utils/ProductAnalytics";
|
|
19
|
-
import MarketingEventUtil
|
|
19
|
+
import MarketingEventUtil, {
|
|
20
|
+
utmAnalyticsProperties,
|
|
21
|
+
} from "../Utils/Marketing/MarketingEventUtil";
|
|
20
22
|
import { MarketingEventType } from "../../Types/Marketing/MarketingEvent";
|
|
23
|
+
import {
|
|
24
|
+
UtmPropertyKeys,
|
|
25
|
+
UtmUrlPropertyKey,
|
|
26
|
+
} from "../../Types/Marketing/Attribution";
|
|
21
27
|
import SessionReplayGateCacheStore from "../Utils/SessionReplay/SessionReplayGateCacheStore";
|
|
22
28
|
import AccessTokenService from "./AccessTokenService";
|
|
23
29
|
import BillingService from "./BillingService";
|
|
@@ -198,6 +204,10 @@ export class ProjectService extends DatabaseService<Model> {
|
|
|
198
204
|
utmMedium: true,
|
|
199
205
|
utmTerm: true,
|
|
200
206
|
utmContent: true,
|
|
207
|
+
utmId: true,
|
|
208
|
+
utmSourcePlatform: true,
|
|
209
|
+
utmCreativeFormat: true,
|
|
210
|
+
utmMarketingTactic: true,
|
|
201
211
|
utmUrl: true,
|
|
202
212
|
clickIds: true,
|
|
203
213
|
firstTouchAttribution: true,
|
|
@@ -348,13 +358,17 @@ export class ProjectService extends DatabaseService<Model> {
|
|
|
348
358
|
data.data.createdOwnerPhone = user.companyPhoneNumber!;
|
|
349
359
|
data.data.createdOwnerCompanyName = user.companyName!;
|
|
350
360
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
data.data
|
|
357
|
-
|
|
361
|
+
/*
|
|
362
|
+
* UTM info, copied field by field off the shared contract rather than
|
|
363
|
+
* hand-listed. Hand-listing is how Project ended up with four columns
|
|
364
|
+
* (utmId and its GA4 siblings) that the schema had but nothing ever wrote.
|
|
365
|
+
*/
|
|
366
|
+
const projectRow: JSONObject = data.data as unknown as JSONObject;
|
|
367
|
+
const userRow: JSONObject = user as unknown as JSONObject;
|
|
368
|
+
|
|
369
|
+
for (const propertyKey of [...UtmPropertyKeys, UtmUrlPropertyKey]) {
|
|
370
|
+
projectRow[propertyKey] = userRow[propertyKey];
|
|
371
|
+
}
|
|
358
372
|
|
|
359
373
|
// Ad attribution info (click IDs + first touch).
|
|
360
374
|
data.data.clickIds = user.clickIds!;
|
|
@@ -572,6 +586,10 @@ export class ProjectService extends DatabaseService<Model> {
|
|
|
572
586
|
utmCampaign: true,
|
|
573
587
|
utmTerm: true,
|
|
574
588
|
utmContent: true,
|
|
589
|
+
utmId: true,
|
|
590
|
+
utmSourcePlatform: true,
|
|
591
|
+
utmCreativeFormat: true,
|
|
592
|
+
utmMarketingTactic: true,
|
|
575
593
|
utmUrl: true,
|
|
576
594
|
clickIds: true,
|
|
577
595
|
firstTouchAttribution: true,
|
|
@@ -950,11 +968,7 @@ These are no longer recorded against the project and have to be cancelled by han
|
|
|
950
968
|
*/
|
|
951
969
|
is_paid_conversion: true,
|
|
952
970
|
has_custom_pricing: data.plan.isCustomPricing(),
|
|
953
|
-
|
|
954
|
-
utm_medium: data.project.utmMedium || "",
|
|
955
|
-
utm_campaign: data.project.utmCampaign || "",
|
|
956
|
-
utm_term: data.project.utmTerm || "",
|
|
957
|
-
utm_content: data.project.utmContent || "",
|
|
971
|
+
...utmAnalyticsProperties(data.project as unknown as JSONObject),
|
|
958
972
|
click_ids: data.project.clickIds || {},
|
|
959
973
|
};
|
|
960
974
|
|
|
@@ -1065,9 +1079,7 @@ These are no longer recorded against the project and have to be cancelled by han
|
|
|
1065
1079
|
oldPlanOrder !== null && newPlanOrder === oldPlanOrder,
|
|
1066
1080
|
is_paid_conversion: oldMonthlyAmountInUSD === 0 && newPlanIsPaid,
|
|
1067
1081
|
has_custom_pricing: data.newPlan.isCustomPricing(),
|
|
1068
|
-
|
|
1069
|
-
utm_medium: data.project.utmMedium || "",
|
|
1070
|
-
utm_campaign: data.project.utmCampaign || "",
|
|
1082
|
+
...utmAnalyticsProperties(data.project as unknown as JSONObject),
|
|
1071
1083
|
click_ids: data.project.clickIds || {},
|
|
1072
1084
|
};
|
|
1073
1085
|
|
|
@@ -1436,9 +1448,7 @@ These are no longer recorded against the project and have to be cancelled by han
|
|
|
1436
1448
|
project_id: createdItem.id?.toString() || "",
|
|
1437
1449
|
project_name: createdItem.name?.toString() || "",
|
|
1438
1450
|
plan: createdItem.planName?.toString() || "",
|
|
1439
|
-
|
|
1440
|
-
utm_medium: createdItem.utmMedium || "",
|
|
1441
|
-
utm_campaign: createdItem.utmCampaign || "",
|
|
1451
|
+
...utmAnalyticsProperties(createdItem as unknown as JSONObject),
|
|
1442
1452
|
click_ids: createdItem.clickIds || {},
|
|
1443
1453
|
},
|
|
1444
1454
|
});
|