@oneuptime/common 12.0.30 → 12.0.31
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/SecurityEvent.ts +48 -16
- package/Models/AnalyticsModels/ThreatIntelIndicator.ts +10 -5
- package/Models/DatabaseModels/AlertSeverity.ts +44 -0
- package/Models/DatabaseModels/DetectionRule.ts +16 -5
- package/Models/DatabaseModels/GoogleSecOpsConnection.ts +14 -5
- package/Models/DatabaseModels/IncidentSeverity.ts +44 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/NetworkDevice.ts +113 -3
- package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +88 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +22 -0
- package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +499 -0
- package/Models/DatabaseModels/ThreatIntelFeed.ts +16 -5
- package/Server/API/GlobalConfigAPI.ts +362 -183
- package/Server/API/TelemetryAPI.ts +42 -4
- package/Server/EnvironmentConfig.ts +112 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.ts +59 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Middleware/MultipartFormData.ts +118 -32
- package/Server/Services/AlertEpisodeLabelRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodeOnCallRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodeOwnerRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodePrivacyRuleEngineService.ts +9 -1
- package/Server/Services/AlertGroupingEngineService.ts +9 -1
- package/Server/Services/AlertLabelRuleEngineService.ts +9 -1
- package/Server/Services/AlertOnCallRuleEngineService.ts +9 -1
- package/Server/Services/AlertOwnerRuleEngineService.ts +9 -1
- package/Server/Services/AlertPrivacyRuleEngineService.ts +9 -1
- package/Server/Services/AlertReminderRuleService.ts +9 -1
- package/Server/Services/AutoRemediationRuleEngineService.ts +9 -1
- package/Server/Services/CephClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/CephClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/CloudResourceLabelRuleEngineService.ts +9 -1
- package/Server/Services/CloudResourceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DashboardLabelRuleEngineService.ts +9 -1
- package/Server/Services/DashboardOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DockerHostLabelRuleEngineService.ts +9 -1
- package/Server/Services/DockerHostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/HostLabelRuleEngineService.ts +9 -1
- package/Server/Services/HostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeOnCallRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodePrivacyRuleEngineService.ts +9 -1
- package/Server/Services/IncidentGroupingEngineService.ts +9 -1
- package/Server/Services/IncidentLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncidentOnCallRuleEngineService.ts +9 -1
- package/Server/Services/IncidentOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentPrivacyRuleEngineService.ts +9 -1
- package/Server/Services/IncidentReminderRuleService.ts +9 -1
- package/Server/Services/IncidentSlaRuleService.ts +9 -1
- package/Server/Services/IncomingCallPolicyLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +9 -1
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/IoTFleetLabelRuleEngineService.ts +9 -1
- package/Server/Services/IoTFleetOwnerRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesResourceService.ts +5 -1
- package/Server/Services/MonitorLabelRuleEngineService.ts +9 -1
- package/Server/Services/MonitorOwnerRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +35 -0
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +96 -0
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceOidTemplateService.ts +201 -0
- package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceService.ts +209 -1
- package/Server/Services/OnCallDutyPolicyLabelRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +9 -1
- package/Server/Services/PodmanHostLabelRuleEngineService.ts +9 -1
- package/Server/Services/PodmanHostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RumApplicationLabelRuleEngineService.ts +9 -1
- package/Server/Services/RumApplicationOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RunbookLabelRuleEngineService.ts +9 -1
- package/Server/Services/RunbookOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RunbookRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +9 -1
- package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +9 -1
- package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ServiceLabelRuleEngineService.ts +9 -1
- package/Server/Services/ServiceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/StatusPageLabelRuleEngineService.ts +9 -1
- package/Server/Services/StatusPageMonitorRuleEngineService.ts +7 -0
- package/Server/Services/StatusPageOwnerRuleEngineService.ts +9 -1
- package/Server/Services/TelemetrySourceMapService.ts +266 -23
- package/Server/Services/UserService.ts +27 -0
- package/Server/Services/WorkflowLabelRuleEngineService.ts +9 -1
- package/Server/Services/WorkflowOwnerRuleEngineService.ts +9 -1
- package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +186 -0
- package/Server/Utils/Monitor/CapturedMetricAttributeUtil.ts +245 -0
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +21 -2
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +55 -21
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +32 -0
- package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +15 -2
- package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +18 -1
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +10 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +34 -0
- package/Server/Utils/Rules/RuleEngineRuleRead.ts +48 -0
- package/Server/Utils/Telemetry/ExceptionSanitizer.ts +14 -1
- package/Server/Utils/Telemetry/LogExceptionExtractor.ts +14 -2
- package/Server/Utils/Telemetry/SourceMapResolver.ts +16 -5
- package/Server/Utils/Telemetry/StackTraceParser.ts +399 -0
- package/Tests/App/Dashboard/EventOverlayHook.test.tsx +125 -0
- package/Tests/App/Dashboard/HeaderImageAssets.test.tsx +93 -0
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3 -3
- package/Tests/App/Dashboard/UserElementEmail.test.tsx +12 -4
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +1 -1
- package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +14 -0
- package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +469 -0
- package/Tests/Models/SecurityDomainAccessControl.test.ts +429 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +657 -0
- package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +84 -6
- package/Tests/Server/API/TelemetryResolveStackTraceAPI.test.ts +805 -0
- package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +32 -7
- package/Tests/Server/Middleware/IdentityRateLimit.test.ts +1144 -0
- package/Tests/Server/Middleware/MultipartFormData.test.ts +618 -3
- package/Tests/Server/Services/MonitorLabelRuleEngineScale.test.ts +520 -0
- package/Tests/Server/Services/NetworkDeviceOidTemplateService.test.ts +332 -0
- package/Tests/Server/Services/NetworkDeviceOidTemplateWriteGuards.test.ts +409 -0
- package/Tests/Server/Services/RuleEngineRuleFetchLimit.test.ts +239 -0
- package/Tests/Server/Services/TelemetrySourceMapService.test.ts +1210 -2
- package/Tests/Server/Services/UserServiceSeatLimit.test.ts +182 -0
- package/Tests/Server/Types/AnalyticsDatabase/SecurityEventModelPermission.test.ts +255 -0
- package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +212 -0
- package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +413 -0
- package/Tests/Server/Utils/CodeRepository.test.ts +689 -0
- package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +495 -0
- package/Tests/Server/Utils/ExceptionSanitizer.test.ts +77 -0
- package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +284 -0
- package/Tests/Server/Utils/Monitor/MonitorCustomMetricAttributes.test.ts +503 -0
- package/Tests/Server/Utils/Monitor/MonitorTemplatePrototypePollution.test.ts +106 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkLogWritePath.test.ts +33 -4
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +14 -4
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +44 -0
- package/Tests/Server/Utils/OpenAPISpec.test.ts +536 -0
- package/Tests/Server/Utils/Rules/RuleEngineRuleRead.test.ts +115 -0
- package/Tests/Server/Utils/StackTraceParser.test.ts +610 -0
- package/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.ts +0 -0
- package/Tests/Server/Utils/Telemetry/SourceMapLimits.test.ts +656 -0
- package/Tests/Server/Utils/Telemetry/SourceMapResolver.test.ts +100 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpOidListUtil.test.ts +454 -0
- package/Tests/Types/SecurityRolePermissions.test.ts +193 -0
- package/Tests/UI/Components/Charts/AnnotationLayout.test.ts +773 -0
- package/Tests/UI/Components/Charts/ChartAnnotationRail.test.tsx +789 -0
- package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +254 -0
- package/Tests/UI/Components/Charts/TimeAnnotation.test.ts +471 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +405 -0
- package/Tests/UI/Components/ErrorMessageRefreshControl.test.tsx +83 -0
- package/Tests/UI/Components/MarkdownConverters.test.ts +686 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableDeleteAndEmptyStates.test.tsx +341 -0
- package/Tests/UI/Components/OrderedStatesList.test.tsx +5 -5
- package/Tests/UI/Components/PendingProjectInvitations.test.tsx +1 -1
- package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +195 -0
- package/Tests/UI/Components/XAxis.test.ts +270 -5
- package/Tests/UI/Components/XAxisDaylightSaving.test.ts +113 -0
- package/Tests/UI/Styles/ChartFocusRing.test.ts +153 -0
- package/Tests/UI/Styles/ChartFocusRingCoverage.test.tsx +377 -0
- package/Tests/UI/Styles/ThemeStylesheet.ts +162 -0
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +507 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +951 -1
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +238 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +1056 -0
- package/Tests/Utils/NetworkDiscovery/ReverseDnsNameUtil.test.ts +882 -0
- package/Types/Date.ts +39 -0
- package/Types/Monitor/SnmpMonitor/SnmpOidListUtil.ts +333 -0
- package/Types/Permission.ts +96 -0
- package/Types/Rum/SessionReplay.ts +21 -0
- package/Types/Telemetry/SourceMap.ts +8 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.tsx +176 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.ts +745 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.tsx +576 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.tsx +204 -0
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +491 -544
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +324 -372
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +487 -540
- package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +7 -3
- package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +14 -3
- package/UI/Components/Charts/Types/ChartEventKind.ts +13 -0
- package/UI/Components/Charts/Types/ReferenceRegionProps.ts +6 -0
- package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +20 -3
- package/UI/Components/Charts/Utils/TimeAnnotation.ts +69 -35
- package/UI/Components/Charts/Utils/XAxis.ts +125 -18
- package/UI/Components/EditionLabel/EditionLabel.tsx +280 -26
- package/UI/Components/ErrorMessage/ErrorMessage.tsx +21 -10
- package/UI/Components/Feed/FeedItem.tsx +4 -5
- package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -2
- package/UI/Components/Header/UserProfile/UserProfile.tsx +1 -2
- package/UI/Components/Image/Image.tsx +20 -3
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +1 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +150 -24
- package/UI/Components/Table/TableHeader.tsx +64 -48
- package/UI/Components/Table/TableRow.tsx +13 -3
- package/UI/Styles/Theme.css +38 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +271 -0
- package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +6 -0
- package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +141 -10
- package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +55 -3
- package/Utils/NetworkDiscovery/ReverseDnsNameUtil.ts +151 -0
- package/Utils/Rules/RuleEngineLimits.ts +32 -0
- package/build/dist/Models/AnalyticsModels/SecurityEvent.js +48 -16
- package/build/dist/Models/AnalyticsModels/SecurityEvent.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js +10 -5
- package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertSeverity.js +46 -1
- package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DetectionRule.js +16 -5
- package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +14 -5
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js +46 -1
- package/build/dist/Models/DatabaseModels/IncidentSeverity.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 +115 -3
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +88 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +519 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js +16 -5
- package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +293 -176
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +31 -3
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +83 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/MultipartFormData.js +93 -28
- package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertGroupingEngineService.js +8 -1
- package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js +8 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DashboardLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DashboardLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/HostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/HostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/HostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentReminderRuleService.js +8 -1
- package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncidentSlaRuleService.js +8 -1
- package/build/dist/Server/Services/IncidentSlaRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesResourceService.js +5 -1
- package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
- package/build/dist/Server/Services/MonitorLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/MonitorLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +30 -21
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +64 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js +180 -0
- package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +154 -1
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServiceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +6 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/TelemetrySourceMapService.js +213 -19
- package/build/dist/Server/Services/TelemetrySourceMapService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +25 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +145 -0
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js +201 -0
- package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +19 -2
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +42 -23
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +29 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +11 -2
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +16 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +10 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +33 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js +37 -0
- package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js +12 -1
- package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +14 -2
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js +15 -5
- package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/StackTraceParser.js +307 -0
- package/build/dist/Server/Utils/Telemetry/StackTraceParser.js.map +1 -1
- package/build/dist/Types/Date.js +27 -0
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js +253 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js.map +1 -0
- package/build/dist/Types/Permission.js +86 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplay.js +19 -0
- package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js +83 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js +531 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js +264 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js +122 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +213 -233
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +139 -152
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +212 -232
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Types/ChartEventKind.js +14 -0
- package/build/dist/UI/Components/Charts/Types/ChartEventKind.js.map +1 -0
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +57 -28
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/XAxis.js +103 -17
- package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +198 -23
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +15 -5
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js +4 -5
- package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -2
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
- package/build/dist/UI/Components/Header/UserProfile/UserProfile.js.map +1 -1
- package/build/dist/UI/Components/Image/Image.js +6 -1
- package/build/dist/UI/Components/Image/Image.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +1 -2
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +104 -23
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Table/TableHeader.js +20 -22
- package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +13 -4
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +153 -0
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +127 -7
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +50 -3
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js +132 -0
- package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js.map +1 -0
- package/build/dist/Utils/Rules/RuleEngineLimits.js +31 -0
- package/build/dist/Utils/Rules/RuleEngineLimits.js.map +1 -0
- package/jest.config.json +1 -0
- package/package.json +2 -2
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
buildDeviceName,
|
|
5
5
|
buildFallbackDeviceName,
|
|
6
6
|
buildNetworkDeviceFromDiscoveredHost,
|
|
7
|
+
getDiscoveredHostDisplayName,
|
|
7
8
|
DiscoveredDeviceScanSource,
|
|
8
9
|
} from "../../../Utils/NetworkDiscovery/DiscoveredDeviceBuilder";
|
|
9
10
|
import NetworkDevice from "../../../Models/DatabaseModels/NetworkDevice";
|
|
@@ -11,7 +12,10 @@ import { DiscoveredNetworkDevice } from "../../../Models/DatabaseModels/NetworkD
|
|
|
11
12
|
import NetworkDeviceMonitoringMethod from "../../../Types/NetworkDevice/NetworkDeviceMonitoringMethod";
|
|
12
13
|
import ObjectID from "../../../Types/ObjectID";
|
|
13
14
|
import { DiscoveryScanSnmpConfig } from "../../../Utils/NetworkDiscovery/SnmpScanConfigUtil";
|
|
14
|
-
import {
|
|
15
|
+
import { MAX_REVERSE_DNS_NAME_LENGTH } from "../../../Utils/NetworkDiscovery/ReverseDnsNameUtil";
|
|
16
|
+
import ColumnLength from "../../../Types/Database/ColumnLength";
|
|
17
|
+
import Slug from "../../../Utils/Slug";
|
|
18
|
+
import { describe, expect, it, test } from "@jest/globals";
|
|
15
19
|
|
|
16
20
|
/*
|
|
17
21
|
* Contract under test — one discovered host maps to one NetworkDevice the
|
|
@@ -555,3 +559,949 @@ describe("the name override", () => {
|
|
|
555
559
|
expect(device.hostname).toBe("10.0.0.5");
|
|
556
560
|
});
|
|
557
561
|
});
|
|
562
|
+
|
|
563
|
+
/*
|
|
564
|
+
* OneUptime issue #3529 — "Network Discovery Scan should perform reverse DNS
|
|
565
|
+
* lookup and display hostnames".
|
|
566
|
+
*
|
|
567
|
+
* The reporter's Review dialog listed 10.18.166.51, .53, .54, .55 on an
|
|
568
|
+
* estate where every one of those addresses has a DNS record. Those rows are
|
|
569
|
+
* hosts with no readable SNMP: with no sysName, `sysName || ipAddress` had
|
|
570
|
+
* nothing left to fall back to. `dnsHostname` is the missing middle term.
|
|
571
|
+
*
|
|
572
|
+
* What these cases pin is the ORDER, and the order is a deliberate judgement
|
|
573
|
+
* rather than a reading of the issue text. The issue asks for the hostname to
|
|
574
|
+
* be "the device name"; sysName is nonetheless kept ahead of it, because
|
|
575
|
+
* sysName is the name the device asserts about itself, it is what every scan
|
|
576
|
+
* imported under before this existed, and demoting it would silently rename
|
|
577
|
+
* devices that already import correctly for people who never asked for
|
|
578
|
+
* anything to change. The PTR name lands exactly where the complaint was —
|
|
579
|
+
* the hosts that had no name at all — and the dialog surfaces both when they
|
|
580
|
+
* disagree, so nothing is hidden by the choice.
|
|
581
|
+
*/
|
|
582
|
+
describe("the reverse-DNS name (issue #3529)", () => {
|
|
583
|
+
describe("precedence", () => {
|
|
584
|
+
test("a host with no sysName is named by its PTR record", () => {
|
|
585
|
+
// The reported case, in one line.
|
|
586
|
+
expect(
|
|
587
|
+
buildDeviceName({
|
|
588
|
+
ipAddress: "10.18.166.51",
|
|
589
|
+
dnsHostname: "core-gw.corp.example.com",
|
|
590
|
+
}),
|
|
591
|
+
).toBe("core-gw.corp.example.com");
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
test("sysName still wins when the host has both", () => {
|
|
595
|
+
expect(
|
|
596
|
+
buildDeviceName({
|
|
597
|
+
ipAddress: "10.18.166.51",
|
|
598
|
+
sysName: "core-switch-01",
|
|
599
|
+
dnsHostname: "sw1.corp.example.com",
|
|
600
|
+
}),
|
|
601
|
+
).toBe("core-switch-01");
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
test("a blank sysName falls through to the PTR name", () => {
|
|
605
|
+
/*
|
|
606
|
+
* A whitespace-only sysName is truthy and is a real thing to read off a
|
|
607
|
+
* device with a half-configured system group. It used to produce a
|
|
608
|
+
* device named " ".
|
|
609
|
+
*/
|
|
610
|
+
expect(
|
|
611
|
+
buildDeviceName({
|
|
612
|
+
ipAddress: "10.18.166.51",
|
|
613
|
+
sysName: " ",
|
|
614
|
+
dnsHostname: "sw1.corp.example.com",
|
|
615
|
+
}),
|
|
616
|
+
).toBe("sw1.corp.example.com");
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
test("a padded sysName is trimmed before it becomes the name", () => {
|
|
620
|
+
/*
|
|
621
|
+
* The whitespace-ONLY case above pins the fall-through; this pins the
|
|
622
|
+
* other half of the same `.trim()`, which nothing asserted. A padded
|
|
623
|
+
* DisplayString is ordinary on real gear, and the padding must not
|
|
624
|
+
* survive: leading spaces go into the varchar, into the slug, and into
|
|
625
|
+
* every site/label rule that matches on the name. Delete the `.trim()`
|
|
626
|
+
* and the sysName is still truthy, still wins the contest, and this
|
|
627
|
+
* reads " core-switch-01 " instead.
|
|
628
|
+
*/
|
|
629
|
+
const paddedHost: DiscoveredNetworkDevice = {
|
|
630
|
+
ipAddress: "10.18.166.51",
|
|
631
|
+
sysName: " core-switch-01 ",
|
|
632
|
+
dnsHostname: "sw1.corp.example.com",
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
expect(getDiscoveredHostDisplayName(paddedHost)).toBe("core-switch-01");
|
|
636
|
+
expect(build({ host: paddedHost }).name).toBe("core-switch-01");
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
test("the address is still the last resort", () => {
|
|
640
|
+
expect(buildDeviceName({ ipAddress: "10.18.166.51" })).toBe(
|
|
641
|
+
"10.18.166.51",
|
|
642
|
+
);
|
|
643
|
+
expect(
|
|
644
|
+
buildDeviceName({ ipAddress: "10.18.166.51", dnsHostname: "" }),
|
|
645
|
+
).toBe("10.18.166.51");
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
test("a host stored before the field existed is named exactly as it was", () => {
|
|
649
|
+
/*
|
|
650
|
+
* Back-compat, and it is not hypothetical: every scan result already in
|
|
651
|
+
* the database predates this field, as does every result from a probe
|
|
652
|
+
* that has not been upgraded yet.
|
|
653
|
+
*/
|
|
654
|
+
expect(
|
|
655
|
+
buildDeviceName({ ipAddress: "10.0.0.5", sysName: "core-switch-01" }),
|
|
656
|
+
).toBe("core-switch-01");
|
|
657
|
+
expect(buildDeviceName({ ipAddress: "10.0.0.5" })).toBe("10.0.0.5");
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
describe("the display name and the device name agree", () => {
|
|
662
|
+
/*
|
|
663
|
+
* The operator ticks a box next to a name and gets a device with that
|
|
664
|
+
* name. The two used to be spelled out separately — the dialog said
|
|
665
|
+
* `sysName || ipAddress` and the builder said the same thing again — and
|
|
666
|
+
* that duplication is what this shared function exists to end.
|
|
667
|
+
*/
|
|
668
|
+
test("the device is created under the clamped display name", () => {
|
|
669
|
+
/*
|
|
670
|
+
* Rows 1-4 are the four naming outcomes; row 5 is what makes the loop
|
|
671
|
+
* mean anything. Every fixture used to be far under the 80-character
|
|
672
|
+
* ceiling, so `truncate` was the identity function on all of them and
|
|
673
|
+
* "buildDeviceName === the display name" held for ANY clamp, including
|
|
674
|
+
* no clamp at all. The long-PTR row is asserted to be genuinely cut at
|
|
675
|
+
* the bottom, so deleting the truncate() reddens this.
|
|
676
|
+
*/
|
|
677
|
+
const longPtrName: string = `${"a".repeat(63)}.${"b".repeat(
|
|
678
|
+
40,
|
|
679
|
+
)}.example.com`;
|
|
680
|
+
|
|
681
|
+
const hosts: Array<DiscoveredNetworkDevice> = [
|
|
682
|
+
{ ipAddress: "10.0.0.1" },
|
|
683
|
+
{ ipAddress: "10.0.0.2", dnsHostname: "gw.corp.example.com" },
|
|
684
|
+
{ ipAddress: "10.0.0.3", sysName: "sw-3" },
|
|
685
|
+
{
|
|
686
|
+
ipAddress: "10.0.0.4",
|
|
687
|
+
sysName: "sw-4",
|
|
688
|
+
dnsHostname: "sw4.corp.example.com",
|
|
689
|
+
},
|
|
690
|
+
{ ipAddress: "10.0.0.5", dnsHostname: longPtrName },
|
|
691
|
+
];
|
|
692
|
+
|
|
693
|
+
for (const discoveredHost of hosts) {
|
|
694
|
+
const displayed: string = getDiscoveredHostDisplayName(discoveredHost);
|
|
695
|
+
|
|
696
|
+
expect(buildDeviceName(discoveredHost)).toBe(
|
|
697
|
+
displayed.substring(0, MAX_DEVICE_NAME_LENGTH),
|
|
698
|
+
);
|
|
699
|
+
|
|
700
|
+
/*
|
|
701
|
+
* And the DEVICE carries that name. This is the half with teeth: the
|
|
702
|
+
* operator ticks a box next to the displayed name, and `device.name`
|
|
703
|
+
* is what the create writes. An edit that gave the builder its own
|
|
704
|
+
* naming rule would pass the assertion above and fail this one.
|
|
705
|
+
*/
|
|
706
|
+
expect(build({ host: discoveredHost }).name).toBe(
|
|
707
|
+
buildDeviceName(discoveredHost),
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// The clamp is exercised rather than skipped: row 5 really is cut.
|
|
712
|
+
const clampedHost: DiscoveredNetworkDevice = hosts[
|
|
713
|
+
hosts.length - 1
|
|
714
|
+
] as DiscoveredNetworkDevice;
|
|
715
|
+
|
|
716
|
+
expect(getDiscoveredHostDisplayName(clampedHost)).not.toBe(
|
|
717
|
+
buildDeviceName(clampedHost),
|
|
718
|
+
);
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
test("the display name is returned unclamped", () => {
|
|
722
|
+
/*
|
|
723
|
+
* The 80-character ceiling exists for the SLUG, not for the eye. A
|
|
724
|
+
* dialog row has its own truncation, and showing the operator a name cut
|
|
725
|
+
* at a different point than the device gets is a smaller problem than
|
|
726
|
+
* pretending the ceiling is a display concern.
|
|
727
|
+
*/
|
|
728
|
+
const longName: string = `${"a".repeat(63)}.${"b".repeat(40)}.example.com`;
|
|
729
|
+
|
|
730
|
+
expect(
|
|
731
|
+
getDiscoveredHostDisplayName({
|
|
732
|
+
ipAddress: "10.0.0.1",
|
|
733
|
+
dnsHostname: longName,
|
|
734
|
+
}),
|
|
735
|
+
).toBe(longName);
|
|
736
|
+
expect(
|
|
737
|
+
buildDeviceName({ ipAddress: "10.0.0.1", dnsHostname: longName }),
|
|
738
|
+
).toHaveLength(MAX_DEVICE_NAME_LENGTH);
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
describe("an untrusted PTR record never becomes a name", () => {
|
|
743
|
+
/*
|
|
744
|
+
* `dnsHostname` is the ONE field in a scan result whose value is chosen by
|
|
745
|
+
* the scanned network. The probe normalises it, and normalizeDiscoveredHosts
|
|
746
|
+
* normalises it again on the way out of the jsonb — but this function is the
|
|
747
|
+
* last point before the value becomes a rendered line and a slugified device
|
|
748
|
+
* name, and a row written by an older probe or straight through the API
|
|
749
|
+
* reaches it without having passed either.
|
|
750
|
+
*/
|
|
751
|
+
test("falls back to the address rather than naming a device after markup", () => {
|
|
752
|
+
expect(
|
|
753
|
+
buildDeviceName({
|
|
754
|
+
ipAddress: "10.18.166.51",
|
|
755
|
+
dnsHostname: "<script>alert(1)</script>",
|
|
756
|
+
}),
|
|
757
|
+
).toBe("10.18.166.51");
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
test("falls back to the address for a name with whitespace in it", () => {
|
|
761
|
+
expect(
|
|
762
|
+
buildDeviceName({
|
|
763
|
+
ipAddress: "10.18.166.51",
|
|
764
|
+
dnsHostname: "core switch",
|
|
765
|
+
}),
|
|
766
|
+
).toBe("10.18.166.51");
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
test("falls back to the address for a PTR that merely restates it", () => {
|
|
770
|
+
/*
|
|
771
|
+
* Not a name. Showing it as one would assert a resolved hostname nobody
|
|
772
|
+
* published, which is worse than showing the address as an address.
|
|
773
|
+
*/
|
|
774
|
+
expect(
|
|
775
|
+
buildDeviceName({
|
|
776
|
+
ipAddress: "10.18.166.51",
|
|
777
|
+
dnsHostname: "10.18.166.51",
|
|
778
|
+
}),
|
|
779
|
+
).toBe("10.18.166.51");
|
|
780
|
+
expect(
|
|
781
|
+
buildDeviceName({
|
|
782
|
+
ipAddress: "10.18.166.51",
|
|
783
|
+
dnsHostname: "51.166.18.10.in-addr.arpa",
|
|
784
|
+
}),
|
|
785
|
+
).toBe("10.18.166.51");
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
test("neither throws nor stringifies on a non-string column", () => {
|
|
789
|
+
/*
|
|
790
|
+
* Two halves, because they fail against two different mutations.
|
|
791
|
+
*
|
|
792
|
+
* 51 is the jsonb-read-at-render-time case: an unguarded `.trim()` is a
|
|
793
|
+
* TypeError thrown inside the modal body. On its own it cannot tell a
|
|
794
|
+
* type-checking normaliser from a COERCING one, because String(51) is
|
|
795
|
+
* "51" and a single all-numeric label is refused anyway.
|
|
796
|
+
*/
|
|
797
|
+
expect(
|
|
798
|
+
buildDeviceName({
|
|
799
|
+
ipAddress: "10.18.166.51",
|
|
800
|
+
dnsHostname: 51 as unknown as string,
|
|
801
|
+
}),
|
|
802
|
+
).toBe("10.18.166.51");
|
|
803
|
+
|
|
804
|
+
/*
|
|
805
|
+
* `true` is the half that can. String(true) is "true" — a syntactically
|
|
806
|
+
* perfect single label that passes every content rule in
|
|
807
|
+
* ReverseDnsNameUtil. Swap the `typeof value !== "string"` guard for
|
|
808
|
+
* String(value) and this host is named "true" instead of by its
|
|
809
|
+
* address, and this line is the only thing in the file that notices.
|
|
810
|
+
*/
|
|
811
|
+
expect(
|
|
812
|
+
buildDeviceName({
|
|
813
|
+
ipAddress: "10.18.166.51",
|
|
814
|
+
dnsHostname: true as unknown as string,
|
|
815
|
+
}),
|
|
816
|
+
).toBe("10.18.166.51");
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
test("stores the normalised form, not the raw answer", () => {
|
|
820
|
+
expect(
|
|
821
|
+
buildDeviceName({
|
|
822
|
+
ipAddress: "10.0.0.1",
|
|
823
|
+
dnsHostname: " gw.corp.example.com. ",
|
|
824
|
+
}),
|
|
825
|
+
).toBe("gw.corp.example.com");
|
|
826
|
+
});
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
describe("the rest of the device", () => {
|
|
830
|
+
test("the address stays the hostname even when the host resolved a name", () => {
|
|
831
|
+
/*
|
|
832
|
+
* The issue asks for this in as many words ("retain the IP address as
|
|
833
|
+
* the address/IP field"), and the system needs it: `hostname` is the
|
|
834
|
+
* registered-host dedup key, what the SNMP poller dials, and what a
|
|
835
|
+
* trap's source IP correlates to. A name here would make a device stop
|
|
836
|
+
* polling the day its reverse zone changed.
|
|
837
|
+
*/
|
|
838
|
+
const device: NetworkDevice = buildNetworkDeviceFromDiscoveredHost({
|
|
839
|
+
projectId: PROJECT_ID,
|
|
840
|
+
host: {
|
|
841
|
+
ipAddress: "10.18.166.51",
|
|
842
|
+
dnsHostname: "core-gw.corp.example.com",
|
|
843
|
+
},
|
|
844
|
+
scan: fullScanSource(),
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
expect(device.hostname).toBe("10.18.166.51");
|
|
848
|
+
expect(device.name).toBe("core-gw.corp.example.com");
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
test("a ping-only host still imports as a monitor-backed device", () => {
|
|
852
|
+
/*
|
|
853
|
+
* Naming must not change WHAT a host imports as. A PTR record says
|
|
854
|
+
* nothing about whether the device can be SNMP-polled.
|
|
855
|
+
*/
|
|
856
|
+
const device: NetworkDevice = buildNetworkDeviceFromDiscoveredHost({
|
|
857
|
+
projectId: PROJECT_ID,
|
|
858
|
+
host: {
|
|
859
|
+
ipAddress: "10.18.166.51",
|
|
860
|
+
snmpReachable: false,
|
|
861
|
+
dnsHostname: "cam-lobby.corp.example.com",
|
|
862
|
+
},
|
|
863
|
+
scan: fullScanSource(),
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
expect(device.name).toBe("cam-lobby.corp.example.com");
|
|
867
|
+
expect(device.monitoringMethod).toBe(
|
|
868
|
+
NetworkDeviceMonitoringMethod.Monitor,
|
|
869
|
+
);
|
|
870
|
+
expect(device.isPollingEnabled).toBe(false);
|
|
871
|
+
expect(device.snmpCommunityString).toBeUndefined();
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
test("the collision fallback appends the address to the PTR name", () => {
|
|
875
|
+
/*
|
|
876
|
+
* Two devices legitimately sharing a name is common — and a shared PTR
|
|
877
|
+
* name is if anything MORE likely than a shared sysName, because a
|
|
878
|
+
* wildcard reverse zone hands every address in a range the same answer.
|
|
879
|
+
* The address is what tells them apart.
|
|
880
|
+
*/
|
|
881
|
+
expect(
|
|
882
|
+
buildFallbackDeviceName({
|
|
883
|
+
ipAddress: "10.18.166.51",
|
|
884
|
+
dnsHostname: "dhcp-pool.corp.example.com",
|
|
885
|
+
}),
|
|
886
|
+
).toBe("dhcp-pool.corp.example.com (10.18.166.51)");
|
|
887
|
+
});
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
/*
|
|
891
|
+
* `sysName` is read out of the SAME verbatim jsonb blob as `dnsHostname`,
|
|
892
|
+
* so its declared `string | undefined` type is a description of what the
|
|
893
|
+
* probe SHOULD send rather than a fact about what is stored. Since
|
|
894
|
+
* getDiscoveredHostDisplayName became the Review dialog's name line, a
|
|
895
|
+
* `(42).trim()` TypeError in here is thrown DURING RENDER: React unmounts
|
|
896
|
+
* the subtree, so one malformed row takes out the entire modal and the
|
|
897
|
+
* operator cannot import any of the hosts the scan found, not just that
|
|
898
|
+
* one. Each of these must fall through to the next naming source instead.
|
|
899
|
+
*/
|
|
900
|
+
describe("an untrusted sysName never reaches .trim()", () => {
|
|
901
|
+
const UNTRUSTED_SYS_NAMES: Array<{ reason: string; value: unknown }> = [
|
|
902
|
+
/*
|
|
903
|
+
* An agent whose sysName OID returned an INTEGER rather than a
|
|
904
|
+
* DisplayString. Discriminating despite "42" being a poor name: unlike
|
|
905
|
+
* `dnsHostname` there is no normaliser behind `sysName ||`, so a
|
|
906
|
+
* String() coercion makes "42" TRUTHY and it wins the naming contest
|
|
907
|
+
* outright, beating a perfectly good PTR record on the same row.
|
|
908
|
+
*
|
|
909
|
+
* (The boolean row that sat here was removed: `true` fails
|
|
910
|
+
* `typeof === "string"` and coerces to a truthy string in exactly the
|
|
911
|
+
* same way this one does, so it could not fail unless this one did.)
|
|
912
|
+
*/
|
|
913
|
+
{ reason: "a number", value: 42 },
|
|
914
|
+
// What a hand-written API row looks like when someone nests the name.
|
|
915
|
+
{ reason: "an object", value: { name: "core-switch-01" } },
|
|
916
|
+
/*
|
|
917
|
+
* The sharpest of the four: `["sw-1"].toString()` is "sw-1", so a
|
|
918
|
+
* String() coercion instead of the typeof guard would quietly ACCEPT
|
|
919
|
+
* this and name a device after a JSON array's join.
|
|
920
|
+
*/
|
|
921
|
+
{ reason: "an array", value: ["sw-1"] },
|
|
922
|
+
/*
|
|
923
|
+
* jsonb stores an explicit null. The old WHY here claimed `??` would
|
|
924
|
+
* miss it, which is backwards — `null ?? ""` is "". The failures this
|
|
925
|
+
* row really pins are the other two shapes the guard could have taken:
|
|
926
|
+
* `host.sysName !== undefined ? host.sysName.trim() : ""` THROWS on
|
|
927
|
+
* null, and `String(null)` is the truthy "null", which would beat the
|
|
928
|
+
* PTR record on the same row and create a device called "null".
|
|
929
|
+
*/
|
|
930
|
+
{ reason: "null", value: null },
|
|
931
|
+
];
|
|
932
|
+
|
|
933
|
+
for (const untrusted of UNTRUSTED_SYS_NAMES) {
|
|
934
|
+
test(`${untrusted.reason} sysName falls through to the PTR name`, () => {
|
|
935
|
+
const host: DiscoveredNetworkDevice = {
|
|
936
|
+
ipAddress: "10.18.166.51",
|
|
937
|
+
sysName: untrusted.value as unknown as string,
|
|
938
|
+
dnsHostname: "core-gw.corp.example.com",
|
|
939
|
+
};
|
|
940
|
+
|
|
941
|
+
expect(getDiscoveredHostDisplayName(host)).toBe(
|
|
942
|
+
"core-gw.corp.example.com",
|
|
943
|
+
);
|
|
944
|
+
expect(buildDeviceName(host)).toBe("core-gw.corp.example.com");
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
test(`${untrusted.reason} sysName falls through to the address`, () => {
|
|
948
|
+
// The same host on an estate with no reverse zone: nothing left but the IP.
|
|
949
|
+
const host: DiscoveredNetworkDevice = {
|
|
950
|
+
ipAddress: "10.18.166.51",
|
|
951
|
+
sysName: untrusted.value as unknown as string,
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
expect(getDiscoveredHostDisplayName(host)).toBe("10.18.166.51");
|
|
955
|
+
expect(buildDeviceName(host)).toBe("10.18.166.51");
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
/*
|
|
961
|
+
* The last resort is the last thing standing between the Review dialog and
|
|
962
|
+
* a blank modal, so it may not throw either — `String(...)` rather than
|
|
963
|
+
* `host.ipAddress.trim()` or a template read of a property.
|
|
964
|
+
*/
|
|
965
|
+
describe("an untrusted address as the last resort", () => {
|
|
966
|
+
test("a numeric address still names the row", () => {
|
|
967
|
+
expect(buildDeviceName({ ipAddress: 42 as unknown as string })).toBe(
|
|
968
|
+
"42",
|
|
969
|
+
);
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
test("a null address degrades to an empty name rather than a throw", () => {
|
|
973
|
+
/*
|
|
974
|
+
* Empty is not a good name; it is a name the create path rejects with
|
|
975
|
+
* a validation error the operator can see, which is strictly better
|
|
976
|
+
* than a TypeError that removes the dialog.
|
|
977
|
+
*/
|
|
978
|
+
expect(
|
|
979
|
+
getDiscoveredHostDisplayName({ ipAddress: null as unknown as string }),
|
|
980
|
+
).toBe("");
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
test("an object address is named by its coercion, not by a throw", () => {
|
|
984
|
+
/*
|
|
985
|
+
* The assertion here was `expect(typeof name).toBe("string")` against a
|
|
986
|
+
* function whose declared return type IS string: the only way it could
|
|
987
|
+
* fail was a throw, and it passed happily with the device named
|
|
988
|
+
* "[object Object]". Pin the value instead.
|
|
989
|
+
*
|
|
990
|
+
* "[object Object]" is a terrible device name and that is the point: it
|
|
991
|
+
* is a name the operator can SEE is wrong and that the create path
|
|
992
|
+
* rejects on its own merits, rather than a TypeError that unmounts the
|
|
993
|
+
* Review dialog. Delete the String(...) coercion and the expression
|
|
994
|
+
* yields the object itself; replace it with a template read and this
|
|
995
|
+
* still holds, which is why the null case above is asserted too.
|
|
996
|
+
*/
|
|
997
|
+
expect(
|
|
998
|
+
buildDeviceName({
|
|
999
|
+
ipAddress: { v4: "10.18.166.51" } as unknown as string,
|
|
1000
|
+
}),
|
|
1001
|
+
).toBe("[object Object]");
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
test("a non-string address is NAMED by coercion but ADDRESSED raw", () => {
|
|
1005
|
+
/*
|
|
1006
|
+
* BOTH readings coerce, and the hostname one matters more than the name.
|
|
1007
|
+
*
|
|
1008
|
+
* `hostname` is the registered-host dedup key:
|
|
1009
|
+
* NetworkDeviceService.getRegisteredHostnames matches it with
|
|
1010
|
+
* `Set.has()` against hostnames read back out of the database as
|
|
1011
|
+
* strings, and `Set.has` does not coerce. A device stored with the
|
|
1012
|
+
* NUMBER 42 in that column would therefore never match its own
|
|
1013
|
+
* registration, so the host would read as unregistered on every review
|
|
1014
|
+
* and import again, and again.
|
|
1015
|
+
*
|
|
1016
|
+
* The dashboard path never reached that, because normalizeDiscoveredHosts
|
|
1017
|
+
* stringifies the address first. The builder is also called directly by
|
|
1018
|
+
* the rule engine, so it coerces on its own account rather than relying
|
|
1019
|
+
* on a caller having been careful.
|
|
1020
|
+
*/
|
|
1021
|
+
const device: NetworkDevice = build({
|
|
1022
|
+
host: { ipAddress: 42 as unknown as string },
|
|
1023
|
+
});
|
|
1024
|
+
|
|
1025
|
+
expect(device.name).toBe("42");
|
|
1026
|
+
expect(device.hostname).toBe("42");
|
|
1027
|
+
expect(typeof device.hostname).toBe("string");
|
|
1028
|
+
});
|
|
1029
|
+
});
|
|
1030
|
+
|
|
1031
|
+
/*
|
|
1032
|
+
* A dnsHostname that is not a string at all, alongside the number and
|
|
1033
|
+
* boolean cases above.
|
|
1034
|
+
*
|
|
1035
|
+
* Every fixture here is chosen so that String(value) is a name the
|
|
1036
|
+
* normaliser would HAPPILY ACCEPT, because that is the only kind that
|
|
1037
|
+
* discriminates. The plain object `{ name: "gw.corp.example.com" }` that
|
|
1038
|
+
* used to sit here proved nothing: String() of it is "[object Object]",
|
|
1039
|
+
* whose spaces and brackets LABEL_PATTERN refuses on their own, so the
|
|
1040
|
+
* case passed against a coercing normaliser exactly as well as against the
|
|
1041
|
+
* type-checking one it claimed to be about.
|
|
1042
|
+
*/
|
|
1043
|
+
describe("an untrusted PTR record of the wrong TYPE", () => {
|
|
1044
|
+
const WRONGLY_TYPED_PTR_ANSWERS: Array<{
|
|
1045
|
+
reason: string;
|
|
1046
|
+
value: unknown;
|
|
1047
|
+
}> = [
|
|
1048
|
+
/*
|
|
1049
|
+
* The realistic one: dns.reverse() answers with an ARRAY of names, and
|
|
1050
|
+
* a probe that forgot to take [0] stores the array. `["gw.corp.
|
|
1051
|
+
* example.com"].toString()` is exactly "gw.corp.example.com", so a
|
|
1052
|
+
* String() coercion would store it verbatim as the device name.
|
|
1053
|
+
*/
|
|
1054
|
+
{
|
|
1055
|
+
reason: "the resolver's whole answer array",
|
|
1056
|
+
value: ["gw.corp.example.com"],
|
|
1057
|
+
},
|
|
1058
|
+
/*
|
|
1059
|
+
* Not a shape JSON.parse can produce, and deliberately so: it is the
|
|
1060
|
+
* question in its pure form. String(value) here IS, byte for byte, the
|
|
1061
|
+
* hostname that would otherwise be stored. Only a real
|
|
1062
|
+
* `typeof value !== "string"` test rejects it — a coercion, a duck-type
|
|
1063
|
+
* ("does it have .trim()?") or an `instanceof String` check would all
|
|
1064
|
+
* name the device gw.corp.example.com off a value that is not a string.
|
|
1065
|
+
*/
|
|
1066
|
+
{
|
|
1067
|
+
reason: "a string-like object",
|
|
1068
|
+
value: {
|
|
1069
|
+
toString: (): string => {
|
|
1070
|
+
return "gw.corp.example.com";
|
|
1071
|
+
},
|
|
1072
|
+
},
|
|
1073
|
+
},
|
|
1074
|
+
];
|
|
1075
|
+
|
|
1076
|
+
for (const answer of WRONGLY_TYPED_PTR_ANSWERS) {
|
|
1077
|
+
test(`${answer.reason} falls back to the address`, () => {
|
|
1078
|
+
const hostWithBadPtr: DiscoveredNetworkDevice = {
|
|
1079
|
+
ipAddress: "10.18.166.51",
|
|
1080
|
+
dnsHostname: answer.value as unknown as string,
|
|
1081
|
+
};
|
|
1082
|
+
|
|
1083
|
+
expect(getDiscoveredHostDisplayName(hostWithBadPtr)).toBe(
|
|
1084
|
+
"10.18.166.51",
|
|
1085
|
+
);
|
|
1086
|
+
// The device, not just the name: a coercion would reach the column.
|
|
1087
|
+
expect(build({ host: hostWithBadPtr }).name).toBe("10.18.166.51");
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
});
|
|
1091
|
+
|
|
1092
|
+
/*
|
|
1093
|
+
* THE WILDCARD REVERSE ZONE.
|
|
1094
|
+
*
|
|
1095
|
+
* A DHCP range is routinely published as one record —
|
|
1096
|
+
* `*.166.18.10.in-addr.arpa IN PTR dhcp-pool.corp.example.com` — so every
|
|
1097
|
+
* address in the range resolves to the SAME name. Nothing about that answer
|
|
1098
|
+
* is malformed, so normalisation keeps it, and the estate the issue came
|
|
1099
|
+
* from is exactly the kind that has one.
|
|
1100
|
+
*
|
|
1101
|
+
* Device names are unique per project, so the second host of such a range
|
|
1102
|
+
* fails its create on a duplicate name. That is what the dashboard's import
|
|
1103
|
+
* retry exists for, and the retry is only useful if the fallback name is
|
|
1104
|
+
* actually DIFFERENT per host — which is what the second half pins.
|
|
1105
|
+
*/
|
|
1106
|
+
describe("a wildcard reverse zone gives many hosts one name", () => {
|
|
1107
|
+
const WILDCARD_PTR_NAME: string = "dhcp-pool.corp.example.com";
|
|
1108
|
+
|
|
1109
|
+
const firstPoolHost: DiscoveredNetworkDevice = {
|
|
1110
|
+
ipAddress: "10.18.166.51",
|
|
1111
|
+
dnsHostname: WILDCARD_PTR_NAME,
|
|
1112
|
+
};
|
|
1113
|
+
const secondPoolHost: DiscoveredNetworkDevice = {
|
|
1114
|
+
ipAddress: "10.18.166.52",
|
|
1115
|
+
dnsHostname: WILDCARD_PTR_NAME,
|
|
1116
|
+
};
|
|
1117
|
+
|
|
1118
|
+
const thirdPoolHost: DiscoveredNetworkDevice = {
|
|
1119
|
+
ipAddress: "10.18.166.53",
|
|
1120
|
+
dnsHostname: WILDCARD_PTR_NAME,
|
|
1121
|
+
};
|
|
1122
|
+
|
|
1123
|
+
const POOL_HOSTS: Array<DiscoveredNetworkDevice> = [
|
|
1124
|
+
firstPoolHost,
|
|
1125
|
+
secondPoolHost,
|
|
1126
|
+
thirdPoolHost,
|
|
1127
|
+
];
|
|
1128
|
+
|
|
1129
|
+
test("three hosts in the range import as one name, three addresses", () => {
|
|
1130
|
+
/*
|
|
1131
|
+
* The second assertion used to be
|
|
1132
|
+
* `expect(buildDeviceName(first)).toBe(buildDeviceName(second))` over
|
|
1133
|
+
* two fixtures built from the same constant — a statement about the
|
|
1134
|
+
* test data, true of any implementation that reads the same field
|
|
1135
|
+
* twice. Phrased over the DEVICES the builder emits it has bite in both
|
|
1136
|
+
* directions: `names.size` is 1 only because the name ignores the
|
|
1137
|
+
* address, and `hostnames.size` is 3 only because the hostname ignores
|
|
1138
|
+
* the name. The tempting edit (put the resolved name in `hostname`)
|
|
1139
|
+
* breaks the second; an edit that disambiguated names eagerly breaks
|
|
1140
|
+
* the first, and would hide the collision the retry below exists for.
|
|
1141
|
+
*/
|
|
1142
|
+
const devices: Array<NetworkDevice> = POOL_HOSTS.map(
|
|
1143
|
+
(poolHost: DiscoveredNetworkDevice) => {
|
|
1144
|
+
return build({ host: poolHost });
|
|
1145
|
+
},
|
|
1146
|
+
);
|
|
1147
|
+
|
|
1148
|
+
const names: Set<string> = new Set<string>(
|
|
1149
|
+
devices.map((device: NetworkDevice) => {
|
|
1150
|
+
return device.name as string;
|
|
1151
|
+
}),
|
|
1152
|
+
);
|
|
1153
|
+
const hostnames: Set<string> = new Set<string>(
|
|
1154
|
+
devices.map((device: NetworkDevice) => {
|
|
1155
|
+
return device.hostname as unknown as string;
|
|
1156
|
+
}),
|
|
1157
|
+
);
|
|
1158
|
+
|
|
1159
|
+
expect(names).toEqual(new Set<string>([WILDCARD_PTR_NAME]));
|
|
1160
|
+
expect(hostnames.size).toBe(POOL_HOSTS.length);
|
|
1161
|
+
});
|
|
1162
|
+
|
|
1163
|
+
test("buildFallbackDeviceName tells them apart by their own address", () => {
|
|
1164
|
+
expect(buildFallbackDeviceName(firstPoolHost)).not.toBe(
|
|
1165
|
+
buildFallbackDeviceName(secondPoolHost),
|
|
1166
|
+
);
|
|
1167
|
+
expect(buildFallbackDeviceName(firstPoolHost)).toBe(
|
|
1168
|
+
"dhcp-pool.corp.example.com (10.18.166.51)",
|
|
1169
|
+
);
|
|
1170
|
+
expect(buildFallbackDeviceName(secondPoolHost)).toBe(
|
|
1171
|
+
"dhcp-pool.corp.example.com (10.18.166.52)",
|
|
1172
|
+
);
|
|
1173
|
+
});
|
|
1174
|
+
|
|
1175
|
+
test("the retry creates the device under the fallback name", () => {
|
|
1176
|
+
/*
|
|
1177
|
+
* End to end, in the shape both import paths actually use: the create
|
|
1178
|
+
* fails on a duplicate name and the caller rebuilds the SAME device
|
|
1179
|
+
* with `name: buildFallbackDeviceName(host)`. Nothing else may move —
|
|
1180
|
+
* `hostname` is still the bare address, which is what the dedup key and
|
|
1181
|
+
* any hostname-keyed rule depend on. Nothing else in the suite passes a
|
|
1182
|
+
* PTR-named host's fallback name through the builder, so an edit that
|
|
1183
|
+
* ignored `data.name`, or that followed the name into `hostname`, would
|
|
1184
|
+
* only be caught here.
|
|
1185
|
+
*/
|
|
1186
|
+
const device: NetworkDevice = build({
|
|
1187
|
+
host: secondPoolHost,
|
|
1188
|
+
name: buildFallbackDeviceName(secondPoolHost),
|
|
1189
|
+
});
|
|
1190
|
+
|
|
1191
|
+
expect(device.name).toBe("dhcp-pool.corp.example.com (10.18.166.52)");
|
|
1192
|
+
expect(device.hostname).toBe("10.18.166.52");
|
|
1193
|
+
});
|
|
1194
|
+
|
|
1195
|
+
test("an address-less host fabricates one shared fallback name", () => {
|
|
1196
|
+
/*
|
|
1197
|
+
* An address-less host gets NO SUFFIX, not a fabricated one.
|
|
1198
|
+
*
|
|
1199
|
+
* The suffix used to be composed with a raw template read —
|
|
1200
|
+
* ` (${host.ipAddress})` — so a missing address produced the literal
|
|
1201
|
+
* token "(undefined)". That is worse than useless here: every
|
|
1202
|
+
* address-less host produced the SAME token, so the fallback handed the
|
|
1203
|
+
* retry a name that collided all over again, failing on the very
|
|
1204
|
+
* duplicate it was retrying.
|
|
1205
|
+
*
|
|
1206
|
+
* The honest answer is that a host with no address cannot be told apart
|
|
1207
|
+
* from another one, so the fallback returns the base name unchanged and
|
|
1208
|
+
* the create fails on a real duplicate. What must never happen is a
|
|
1209
|
+
* name that LOOKS address-qualified while carrying no address.
|
|
1210
|
+
*/
|
|
1211
|
+
const addresslessHost: DiscoveredNetworkDevice = {
|
|
1212
|
+
dnsHostname: WILDCARD_PTR_NAME,
|
|
1213
|
+
} as unknown as DiscoveredNetworkDevice;
|
|
1214
|
+
|
|
1215
|
+
const fallbackName: string = buildFallbackDeviceName(addresslessHost);
|
|
1216
|
+
|
|
1217
|
+
expect(fallbackName).toBe(WILDCARD_PTR_NAME);
|
|
1218
|
+
expect(fallbackName).not.toContain("undefined");
|
|
1219
|
+
expect(fallbackName).not.toContain("(");
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
test("a null address is composed into the name as the token (null)", () => {
|
|
1223
|
+
/*
|
|
1224
|
+
* ONE value, ONE reading — which is the point of the fix.
|
|
1225
|
+
*
|
|
1226
|
+
* A null address used to be read two ways: "" by the display path
|
|
1227
|
+
* (`String(host.ipAddress ?? "")`) and " (null)" by the fallback path,
|
|
1228
|
+
* which interpolated it raw. Two readings of one field in two functions
|
|
1229
|
+
* that have to agree about the same host is how a retry ends up
|
|
1230
|
+
* composing a name nobody can act on.
|
|
1231
|
+
*/
|
|
1232
|
+
const nullAddressHost: DiscoveredNetworkDevice = {
|
|
1233
|
+
ipAddress: null as unknown as string,
|
|
1234
|
+
dnsHostname: WILDCARD_PTR_NAME,
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1237
|
+
expect(buildFallbackDeviceName(nullAddressHost)).toBe(WILDCARD_PTR_NAME);
|
|
1238
|
+
expect(buildFallbackDeviceName(nullAddressHost)).not.toContain("null)");
|
|
1239
|
+
});
|
|
1240
|
+
});
|
|
1241
|
+
|
|
1242
|
+
/*
|
|
1243
|
+
* FALLBACK NAME ARITHMETIC at both extremes at once.
|
|
1244
|
+
*
|
|
1245
|
+
* The longest name DNS can express (253 characters) combined with the
|
|
1246
|
+
* widest address is the worst case the composition has to survive, and a
|
|
1247
|
+
* PTR name is the one naming source that can hit its own ceiling with no
|
|
1248
|
+
* help from a misconfigured device. Two things have to hold: the composed
|
|
1249
|
+
* name still fits under the ceiling the slug needs, and the ADDRESS
|
|
1250
|
+
* survives the cut. A fallback that truncated the address away would hand
|
|
1251
|
+
* both hosts of a wildcard range the same name again — the exact collision
|
|
1252
|
+
* it is there to break.
|
|
1253
|
+
*
|
|
1254
|
+
* "Widest address" is IPv6, not 255.255.255.255. A full v6 address is 39
|
|
1255
|
+
* characters, so its suffix is 42 — more than half the whole ceiling, and
|
|
1256
|
+
* 24 characters wider than the v4 case. The v4 rows come first because
|
|
1257
|
+
* they are the ordinary case; the v6 rows at the end are the real extreme,
|
|
1258
|
+
* and the probe resolves ip6.arpa PTRs, so v6 hosts are in scope.
|
|
1259
|
+
*/
|
|
1260
|
+
describe("the fallback name at the longest PTR name and the widest address", () => {
|
|
1261
|
+
// 63 + 1 + 63 + 1 + 63 + 1 + 61 = 253: maximal labels, maximal total.
|
|
1262
|
+
const MAXIMAL_PTR_NAME: string = `${"a".repeat(63)}.${"b".repeat(
|
|
1263
|
+
63,
|
|
1264
|
+
)}.${"c".repeat(63)}.${"d".repeat(61)}`;
|
|
1265
|
+
|
|
1266
|
+
const WIDEST_ADDRESS_SUFFIX: string = " (255.255.255.255)";
|
|
1267
|
+
|
|
1268
|
+
test("the maximal name is a name this builder actually accepts", () => {
|
|
1269
|
+
/*
|
|
1270
|
+
* Anti-vacuity for everything below: if normalisation rejected a
|
|
1271
|
+
* 253-character name, every case here would be measuring the ADDRESS
|
|
1272
|
+
* fallback and would pass for the wrong reason.
|
|
1273
|
+
*/
|
|
1274
|
+
expect(MAXIMAL_PTR_NAME).toHaveLength(MAX_REVERSE_DNS_NAME_LENGTH);
|
|
1275
|
+
expect(
|
|
1276
|
+
buildDeviceName({
|
|
1277
|
+
ipAddress: "255.255.255.255",
|
|
1278
|
+
dnsHostname: MAXIMAL_PTR_NAME,
|
|
1279
|
+
}),
|
|
1280
|
+
).toBe(MAXIMAL_PTR_NAME.substring(0, MAX_DEVICE_NAME_LENGTH));
|
|
1281
|
+
});
|
|
1282
|
+
|
|
1283
|
+
test("the composed name uses the whole ceiling and keeps the address", () => {
|
|
1284
|
+
/*
|
|
1285
|
+
* The re-derived expectation is gone. This used to assert the base
|
|
1286
|
+
* equals `MAXIMAL_PTR_NAME.substring(0, MAX - suffix.length)`, which is
|
|
1287
|
+
* buildFallbackDeviceName's own arithmetic restated: an implementation
|
|
1288
|
+
* that computed the WRONG cut would compute it identically on both
|
|
1289
|
+
* sides and still pass. The contract instead — all 80 characters are
|
|
1290
|
+
* used, the suffix is the host's address in full (it is never what
|
|
1291
|
+
* gives way, or the wildcard range collides again), and what precedes
|
|
1292
|
+
* it is a genuine prefix of the PTR name rather than some other string.
|
|
1293
|
+
*/
|
|
1294
|
+
const name: string = buildFallbackDeviceName({
|
|
1295
|
+
ipAddress: "255.255.255.255",
|
|
1296
|
+
dnsHostname: MAXIMAL_PTR_NAME,
|
|
1297
|
+
});
|
|
1298
|
+
|
|
1299
|
+
expect(name).toHaveLength(MAX_DEVICE_NAME_LENGTH);
|
|
1300
|
+
expect(name.endsWith(WIDEST_ADDRESS_SUFFIX)).toBe(true);
|
|
1301
|
+
|
|
1302
|
+
const base: string = name.substring(
|
|
1303
|
+
0,
|
|
1304
|
+
name.length - WIDEST_ADDRESS_SUFFIX.length,
|
|
1305
|
+
);
|
|
1306
|
+
|
|
1307
|
+
expect(base.length).toBeGreaterThan(0);
|
|
1308
|
+
expect(MAXIMAL_PTR_NAME.startsWith(base)).toBe(true);
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1311
|
+
test("two maximal-name hosts still get different fallback names", () => {
|
|
1312
|
+
/*
|
|
1313
|
+
* The point of the whole fallback, at the length where losing the
|
|
1314
|
+
* address is most tempting: these two share 253 characters of name and
|
|
1315
|
+
* differ only in their last octet.
|
|
1316
|
+
*/
|
|
1317
|
+
expect(
|
|
1318
|
+
buildFallbackDeviceName({
|
|
1319
|
+
ipAddress: "255.255.255.255",
|
|
1320
|
+
dnsHostname: MAXIMAL_PTR_NAME,
|
|
1321
|
+
}),
|
|
1322
|
+
).not.toBe(
|
|
1323
|
+
buildFallbackDeviceName({
|
|
1324
|
+
ipAddress: "255.255.255.254",
|
|
1325
|
+
dnsHostname: MAXIMAL_PTR_NAME,
|
|
1326
|
+
}),
|
|
1327
|
+
);
|
|
1328
|
+
});
|
|
1329
|
+
|
|
1330
|
+
/*
|
|
1331
|
+
* IPV6 — the actual worst case, and untested anywhere in the feature
|
|
1332
|
+
* until now. 39 characters of address means a 42-character suffix, so
|
|
1333
|
+
* the base is cut to 38: more than half the composed name is the address.
|
|
1334
|
+
* The `Math.max(1, MAX_DEVICE_NAME_LENGTH - suffix.length)` in
|
|
1335
|
+
* buildFallbackDeviceName is written to survive this; nothing proved it,
|
|
1336
|
+
* and a v4-only reading of "the widest address" would not have noticed a
|
|
1337
|
+
* regression that only bites past an 18-character suffix.
|
|
1338
|
+
*/
|
|
1339
|
+
const FULL_IPV6_ADDRESS: string = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
|
|
1340
|
+
const IPV6_SUFFIX: string = ` (${FULL_IPV6_ADDRESS})`;
|
|
1341
|
+
|
|
1342
|
+
test("an IPv6 address takes over half the ceiling and still fits", () => {
|
|
1343
|
+
// Anti-vacuity: this really is the wider of the two suffixes.
|
|
1344
|
+
expect(IPV6_SUFFIX.length).toBeGreaterThan(WIDEST_ADDRESS_SUFFIX.length);
|
|
1345
|
+
|
|
1346
|
+
const name: string = buildFallbackDeviceName({
|
|
1347
|
+
ipAddress: FULL_IPV6_ADDRESS,
|
|
1348
|
+
dnsHostname: MAXIMAL_PTR_NAME,
|
|
1349
|
+
});
|
|
1350
|
+
|
|
1351
|
+
expect(name).toHaveLength(MAX_DEVICE_NAME_LENGTH);
|
|
1352
|
+
expect(name.endsWith(IPV6_SUFFIX)).toBe(true);
|
|
1353
|
+
expect(
|
|
1354
|
+
MAXIMAL_PTR_NAME.startsWith(
|
|
1355
|
+
name.substring(0, name.length - IPV6_SUFFIX.length),
|
|
1356
|
+
),
|
|
1357
|
+
).toBe(true);
|
|
1358
|
+
|
|
1359
|
+
/*
|
|
1360
|
+
* And it still slugs. Asserted here rather than for the v4 case
|
|
1361
|
+
* because the maths is genuinely different: slugify's `remove` set
|
|
1362
|
+
* strips the colons and the brackets, so a v6 fallback's slug base is
|
|
1363
|
+
* nine characters SHORTER than its name.
|
|
1364
|
+
*/
|
|
1365
|
+
expect(Slug.getSlug(name).length).toBeLessThanOrEqual(ColumnLength.Slug);
|
|
1366
|
+
});
|
|
1367
|
+
|
|
1368
|
+
test("two IPv6 hosts in one wildcard zone still get different names", () => {
|
|
1369
|
+
/*
|
|
1370
|
+
* Where "cut the suffix instead of the base" would collide: these two
|
|
1371
|
+
* share 253 characters of PTR name and differ only in the last group of
|
|
1372
|
+
* an address that occupies 42 of the 80 characters available.
|
|
1373
|
+
*/
|
|
1374
|
+
expect(
|
|
1375
|
+
buildFallbackDeviceName({
|
|
1376
|
+
ipAddress: FULL_IPV6_ADDRESS,
|
|
1377
|
+
dnsHostname: MAXIMAL_PTR_NAME,
|
|
1378
|
+
}),
|
|
1379
|
+
).not.toBe(
|
|
1380
|
+
buildFallbackDeviceName({
|
|
1381
|
+
ipAddress: "2001:0db8:85a3:0000:0000:8a2e:0370:7335",
|
|
1382
|
+
dnsHostname: MAXIMAL_PTR_NAME,
|
|
1383
|
+
}),
|
|
1384
|
+
);
|
|
1385
|
+
});
|
|
1386
|
+
|
|
1387
|
+
/*
|
|
1388
|
+
* SLUG HEADROOM — the ceiling that actually bites.
|
|
1389
|
+
*
|
|
1390
|
+
* NetworkDevice.name is varchar(100) but @SlugifyColumn writes a slug
|
|
1391
|
+
* beside it, and Slug.getSlug appends a dash and ten digits into its own
|
|
1392
|
+
* varchar(100). So a name of 95 characters fits the name column and fails
|
|
1393
|
+
* the CREATE on the slug, with an error that says nothing about names.
|
|
1394
|
+
* MAX_DEVICE_NAME_LENGTH is 80 for this reason and nothing else, so the
|
|
1395
|
+
* arithmetic is asserted here against the real column length and the real
|
|
1396
|
+
* slug function rather than restated as a comment.
|
|
1397
|
+
*/
|
|
1398
|
+
test("the ceiling is what keeps the slug inside its own column", () => {
|
|
1399
|
+
/*
|
|
1400
|
+
* This replaces three tests that were each measuring less than they
|
|
1401
|
+
* claimed: one asserted `MAX_DEVICE_NAME_LENGTH + "-1234567890".length
|
|
1402
|
+
* <= ColumnLength.Slug`, pure arithmetic over two constants that
|
|
1403
|
+
* invoked none of the code under test and hard-coded Faker's suffix
|
|
1404
|
+
* shape as a literal; the other two slugged names that slugify SHRINKS,
|
|
1405
|
+
* so they had headroom the real worst case does not.
|
|
1406
|
+
*
|
|
1407
|
+
* The fixture is chosen to be that worst case. Every dotted PTR name
|
|
1408
|
+
* loses a character per dot on the way into a slug (slugify's `remove`
|
|
1409
|
+
* set eats them), so a PTR-named device can never be the widest slug a
|
|
1410
|
+
* name of this length produces. A hyphenated sysName has nothing to
|
|
1411
|
+
* remove, so its slug base is the full 80 characters — and 255-octet
|
|
1412
|
+
* sysNames are routine on real gear, which is why the clamp exists.
|
|
1413
|
+
*
|
|
1414
|
+
* Raise MAX_DEVICE_NAME_LENGTH past what the slug column can hold and
|
|
1415
|
+
* this fails at the constant, rather than in production on whichever
|
|
1416
|
+
* device happens to have a long enough name.
|
|
1417
|
+
*/
|
|
1418
|
+
const SLUG_PROBE: string = "device";
|
|
1419
|
+
// Measured off the real Slug, not restated: it tracks Faker's suffix.
|
|
1420
|
+
const slugSuffixLength: number =
|
|
1421
|
+
Slug.getSlug(SLUG_PROBE).length - SLUG_PROBE.length;
|
|
1422
|
+
|
|
1423
|
+
const name: string = buildDeviceName({
|
|
1424
|
+
ipAddress: "10.18.166.51",
|
|
1425
|
+
sysName: "long-sysname-".repeat(20),
|
|
1426
|
+
});
|
|
1427
|
+
|
|
1428
|
+
expect(name).toHaveLength(MAX_DEVICE_NAME_LENGTH);
|
|
1429
|
+
|
|
1430
|
+
const slug: string = Slug.getSlug(name);
|
|
1431
|
+
|
|
1432
|
+
// Nothing was removed: the whole clamped name is still in the slug.
|
|
1433
|
+
expect(slug.substring(0, slug.length - slugSuffixLength)).toBe(
|
|
1434
|
+
name.toLowerCase(),
|
|
1435
|
+
);
|
|
1436
|
+
expect(slug.length).toBeLessThanOrEqual(ColumnLength.Slug);
|
|
1437
|
+
});
|
|
1438
|
+
});
|
|
1439
|
+
|
|
1440
|
+
/*
|
|
1441
|
+
* `hostname` is the registered-host dedup key, what the SNMP poller dials,
|
|
1442
|
+
* and what a trap's source IP is correlated to — so it is the ADDRESS for
|
|
1443
|
+
* every host, whatever the host ended up being NAMED. Table-driven across
|
|
1444
|
+
* both naming sources because the risk is a future edit that "uses the
|
|
1445
|
+
* resolved name where we have one": that would look correct on five of
|
|
1446
|
+
* these six rows and would silently stop a device polling the day its
|
|
1447
|
+
* reverse zone changed.
|
|
1448
|
+
*/
|
|
1449
|
+
describe("the address is the hostname for every naming combination", () => {
|
|
1450
|
+
const NAMING_COMBINATIONS: Array<{
|
|
1451
|
+
reason: string;
|
|
1452
|
+
host: DiscoveredNetworkDevice;
|
|
1453
|
+
expectedName: string;
|
|
1454
|
+
}> = [
|
|
1455
|
+
{
|
|
1456
|
+
reason: "sysName and a usable PTR name",
|
|
1457
|
+
host: {
|
|
1458
|
+
ipAddress: "10.18.166.51",
|
|
1459
|
+
sysName: "core-switch-01",
|
|
1460
|
+
dnsHostname: "sw1.corp.example.com",
|
|
1461
|
+
},
|
|
1462
|
+
expectedName: "core-switch-01",
|
|
1463
|
+
},
|
|
1464
|
+
{
|
|
1465
|
+
reason: "sysName and no PTR name",
|
|
1466
|
+
host: { ipAddress: "10.18.166.51", sysName: "core-switch-01" },
|
|
1467
|
+
expectedName: "core-switch-01",
|
|
1468
|
+
},
|
|
1469
|
+
{
|
|
1470
|
+
reason: "sysName and a PTR name that normalises away",
|
|
1471
|
+
host: {
|
|
1472
|
+
ipAddress: "10.18.166.51",
|
|
1473
|
+
sysName: "core-switch-01",
|
|
1474
|
+
dnsHostname: "51.166.18.10.in-addr.arpa",
|
|
1475
|
+
},
|
|
1476
|
+
expectedName: "core-switch-01",
|
|
1477
|
+
},
|
|
1478
|
+
{
|
|
1479
|
+
reason: "no sysName and a usable PTR name",
|
|
1480
|
+
host: {
|
|
1481
|
+
ipAddress: "10.18.166.51",
|
|
1482
|
+
dnsHostname: "sw1.corp.example.com",
|
|
1483
|
+
},
|
|
1484
|
+
expectedName: "sw1.corp.example.com",
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
reason: "no sysName and no PTR name",
|
|
1488
|
+
host: { ipAddress: "10.18.166.51" },
|
|
1489
|
+
expectedName: "10.18.166.51",
|
|
1490
|
+
},
|
|
1491
|
+
{
|
|
1492
|
+
reason: "no sysName and a PTR name that normalises away",
|
|
1493
|
+
host: { ipAddress: "10.18.166.51", dnsHostname: "core switch" },
|
|
1494
|
+
expectedName: "10.18.166.51",
|
|
1495
|
+
},
|
|
1496
|
+
];
|
|
1497
|
+
|
|
1498
|
+
for (const combination of NAMING_COMBINATIONS) {
|
|
1499
|
+
test(`${combination.reason}: named ${combination.expectedName}, addressed 10.18.166.51`, () => {
|
|
1500
|
+
const device: NetworkDevice = build({ host: combination.host });
|
|
1501
|
+
|
|
1502
|
+
expect(device.name).toBe(combination.expectedName);
|
|
1503
|
+
expect(device.hostname).toBe("10.18.166.51");
|
|
1504
|
+
});
|
|
1505
|
+
}
|
|
1506
|
+
});
|
|
1507
|
+
});
|