@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
|
@@ -0,0 +1,805 @@
|
|
|
1
|
+
import CommonAPI from "../../../Server/API/CommonAPI";
|
|
2
|
+
import ProjectService from "../../../Server/Services/ProjectService";
|
|
3
|
+
import TelemetrySourceMapService from "../../../Server/Services/TelemetrySourceMapService";
|
|
4
|
+
import SourceMapResolver, {
|
|
5
|
+
MAX_FRAMES_PER_RESOLVE_REQUEST,
|
|
6
|
+
MAX_FRAMES_TO_RESOLVE,
|
|
7
|
+
} from "../../../Server/Utils/Telemetry/SourceMapResolver";
|
|
8
|
+
import {
|
|
9
|
+
ExpressRequest,
|
|
10
|
+
ExpressResponse,
|
|
11
|
+
NextFunction,
|
|
12
|
+
} from "../../../Server/Utils/Express";
|
|
13
|
+
import Response from "../../../Server/Utils/Response";
|
|
14
|
+
import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
15
|
+
import Dictionary from "../../../Types/Dictionary";
|
|
16
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
17
|
+
import Exception from "../../../Types/Exception/Exception";
|
|
18
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
19
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
20
|
+
import Permission, {
|
|
21
|
+
UserPermission,
|
|
22
|
+
UserTenantAccessPermission,
|
|
23
|
+
} from "../../../Types/Permission";
|
|
24
|
+
import {
|
|
25
|
+
MinifiedStackFrame,
|
|
26
|
+
ResolveStackTraceResult,
|
|
27
|
+
} from "../../../Types/Telemetry/SourceMap";
|
|
28
|
+
import UserType from "../../../Types/UserType";
|
|
29
|
+
import {
|
|
30
|
+
afterEach,
|
|
31
|
+
beforeAll,
|
|
32
|
+
beforeEach,
|
|
33
|
+
describe,
|
|
34
|
+
expect,
|
|
35
|
+
jest,
|
|
36
|
+
test,
|
|
37
|
+
} from "@jest/globals";
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
* ---------------------------------------------------------------------------
|
|
41
|
+
* POST /telemetry/exceptions/resolve-stack-trace — the frames-array cap
|
|
42
|
+
* ---------------------------------------------------------------------------
|
|
43
|
+
*
|
|
44
|
+
* The handler takes a caller-supplied `frames` array and hands it to
|
|
45
|
+
* SourceMapResolver.sanitizeMinifiedStackFrames, which never throws and never
|
|
46
|
+
* truncates: it walks every element and returns one output frame per object it
|
|
47
|
+
* sees. Downstream, resolveFramesForService only *resolves* the first
|
|
48
|
+
* MAX_FRAMES_TO_RESOLVE frames, but it still copies the whole array into the
|
|
49
|
+
* response. So before this cap existed, the only bound on the work (and the
|
|
50
|
+
* response size) a single request could ask for was the body-size limit —
|
|
51
|
+
* ~200k frames of `{}` fit inside a few megabytes of JSON.
|
|
52
|
+
*
|
|
53
|
+
* MAX_FRAMES_PER_RESOLVE_REQUEST closes that. The cases below pin the three
|
|
54
|
+
* things that make it correct rather than merely present: it is a `>` bound
|
|
55
|
+
* (a full 10000-frame trace still resolves), it sits AFTER the Array.isArray
|
|
56
|
+
* guard (so a non-array keeps its own precise error), and it sits BEFORE
|
|
57
|
+
* sanitize (so an oversized array is refused instead of being quietly walked
|
|
58
|
+
* end to end and reduced to []).
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
type RouterFunction = (
|
|
62
|
+
req: ExpressRequest,
|
|
63
|
+
res: ExpressResponse,
|
|
64
|
+
next: NextFunction,
|
|
65
|
+
) => void | Promise<void>;
|
|
66
|
+
|
|
67
|
+
type RecordedRoute = {
|
|
68
|
+
method: string;
|
|
69
|
+
uri: string;
|
|
70
|
+
handlers: Array<RouterFunction>;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const recordedRoutes: Array<RecordedRoute> = [];
|
|
74
|
+
|
|
75
|
+
type RecordRouteFunction = (
|
|
76
|
+
method: string,
|
|
77
|
+
) => (uri: string, ...handlers: Array<RouterFunction>) => void;
|
|
78
|
+
|
|
79
|
+
const recordRoute: RecordRouteFunction = (method: string) => {
|
|
80
|
+
return (uri: string, ...handlers: Array<RouterFunction>): void => {
|
|
81
|
+
recordedRoutes.push({
|
|
82
|
+
method: method.toUpperCase(),
|
|
83
|
+
uri: uri,
|
|
84
|
+
handlers: handlers,
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const telemetryRouter: JSONObject = {
|
|
90
|
+
get: recordRoute("get"),
|
|
91
|
+
post: recordRoute("post"),
|
|
92
|
+
put: recordRoute("put"),
|
|
93
|
+
delete: recordRoute("delete"),
|
|
94
|
+
} as unknown as JSONObject;
|
|
95
|
+
|
|
96
|
+
jest.mock("../../../Server/Utils/Express", () => {
|
|
97
|
+
return {
|
|
98
|
+
getRouter: () => {
|
|
99
|
+
return telemetryRouter;
|
|
100
|
+
},
|
|
101
|
+
getClientIp: () => {
|
|
102
|
+
return "203.0.113.7";
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
jest.mock("../../../Server/Utils/Response", () => {
|
|
108
|
+
return {
|
|
109
|
+
sendEntityArrayResponse: jest.fn(),
|
|
110
|
+
sendJsonObjectResponse: jest.fn(),
|
|
111
|
+
sendEmptySuccessResponse: jest.fn(),
|
|
112
|
+
sendEntityResponse: jest.fn(),
|
|
113
|
+
sendErrorResponse: jest.fn(),
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const RESOLVE_ROUTE: string = "/telemetry/exceptions/resolve-stack-trace";
|
|
118
|
+
|
|
119
|
+
type FindRouteFunction = (uri: string) => RecordedRoute;
|
|
120
|
+
|
|
121
|
+
const findRoute: FindRouteFunction = (uri: string): RecordedRoute => {
|
|
122
|
+
const route: RecordedRoute | undefined = recordedRoutes.find(
|
|
123
|
+
(candidate: RecordedRoute): boolean => {
|
|
124
|
+
return candidate.method === "POST" && candidate.uri === uri;
|
|
125
|
+
},
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
if (!route) {
|
|
129
|
+
throw new Error(`Route not registered: ${uri}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return route;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
type CallResult = {
|
|
136
|
+
/* Exception handed to Response.sendErrorResponse by a guard or the handler. */
|
|
137
|
+
deniedWith: Exception | undefined;
|
|
138
|
+
/* Exception thrown out of the handler into express' error path. */
|
|
139
|
+
thrownToNext: unknown;
|
|
140
|
+
/* True when the final route handler was actually entered. */
|
|
141
|
+
reachedHandler: boolean;
|
|
142
|
+
jsonBody: JSONObject | undefined;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/*
|
|
146
|
+
* Runs the recorded route's middleware chain for real, starting at
|
|
147
|
+
* requireUserAuthentication. Index 0 is getUserMiddleware, whose only job is
|
|
148
|
+
* to populate the session fields these fixtures set directly — running it
|
|
149
|
+
* would need a live session store and would prove nothing about the cap.
|
|
150
|
+
*/
|
|
151
|
+
type CallRouteFunction = (data: {
|
|
152
|
+
request: JSONObject;
|
|
153
|
+
body: unknown;
|
|
154
|
+
}) => Promise<CallResult>;
|
|
155
|
+
|
|
156
|
+
const callRoute: CallRouteFunction = async (data: {
|
|
157
|
+
request: JSONObject;
|
|
158
|
+
body: unknown;
|
|
159
|
+
}): Promise<CallResult> => {
|
|
160
|
+
const route: RecordedRoute = findRoute(RESOLVE_ROUTE);
|
|
161
|
+
|
|
162
|
+
const req: ExpressRequest = {
|
|
163
|
+
...data.request,
|
|
164
|
+
body: data.body,
|
|
165
|
+
params: {},
|
|
166
|
+
query: {},
|
|
167
|
+
headers: { "user-agent": "jest-agent" },
|
|
168
|
+
} as unknown as ExpressRequest;
|
|
169
|
+
|
|
170
|
+
const res: ExpressResponse = {
|
|
171
|
+
setHeader: (): void => {
|
|
172
|
+
// no-op
|
|
173
|
+
},
|
|
174
|
+
send: (): void => {
|
|
175
|
+
// no-op
|
|
176
|
+
},
|
|
177
|
+
status: jest.fn().mockReturnThis(),
|
|
178
|
+
json: jest.fn(),
|
|
179
|
+
} as unknown as ExpressResponse;
|
|
180
|
+
|
|
181
|
+
const outcome: { thrownToNext: unknown; reachedHandler: boolean } = {
|
|
182
|
+
thrownToNext: undefined,
|
|
183
|
+
reachedHandler: false,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
for (let index: number = 1; index < route.handlers.length; index++) {
|
|
187
|
+
const handler: RouterFunction | undefined = route.handlers[index];
|
|
188
|
+
|
|
189
|
+
if (!handler) {
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (index === route.handlers.length - 1) {
|
|
194
|
+
outcome.reachedHandler = true;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const step: { calledNext: boolean } = { calledNext: false };
|
|
198
|
+
|
|
199
|
+
const next: NextFunction = ((error?: unknown): void => {
|
|
200
|
+
step.calledNext = true;
|
|
201
|
+
|
|
202
|
+
if (error) {
|
|
203
|
+
outcome.thrownToNext = error;
|
|
204
|
+
}
|
|
205
|
+
}) as unknown as NextFunction;
|
|
206
|
+
|
|
207
|
+
await handler(req, res, next);
|
|
208
|
+
|
|
209
|
+
// A guard (or the handler) that answered the request never calls next.
|
|
210
|
+
if (!step.calledNext) {
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const sendErrorResponse: jest.Mock =
|
|
216
|
+
Response.sendErrorResponse as unknown as jest.Mock;
|
|
217
|
+
const sendJsonObjectResponse: jest.Mock =
|
|
218
|
+
Response.sendJsonObjectResponse as unknown as jest.Mock;
|
|
219
|
+
|
|
220
|
+
const errorCall: Array<unknown> | undefined = sendErrorResponse.mock
|
|
221
|
+
.calls[0] as Array<unknown> | undefined;
|
|
222
|
+
const jsonCall: Array<unknown> | undefined = sendJsonObjectResponse.mock
|
|
223
|
+
.calls[0] as Array<unknown> | undefined;
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
deniedWith: errorCall ? (errorCall[2] as Exception) : undefined,
|
|
227
|
+
thrownToNext: outcome.thrownToNext,
|
|
228
|
+
reachedHandler: outcome.reachedHandler,
|
|
229
|
+
jsonBody: jsonCall ? (jsonCall[2] as JSONObject) : undefined,
|
|
230
|
+
};
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
type BuildPrincipalFunction = (data: {
|
|
234
|
+
projectId: ObjectID;
|
|
235
|
+
userId: ObjectID;
|
|
236
|
+
}) => JSONObject;
|
|
237
|
+
|
|
238
|
+
const buildPrincipal: BuildPrincipalFunction = (data: {
|
|
239
|
+
projectId: ObjectID;
|
|
240
|
+
userId: ObjectID;
|
|
241
|
+
}): JSONObject => {
|
|
242
|
+
/*
|
|
243
|
+
* isBlockPermission must be an explicit false: getUserPermissions filters
|
|
244
|
+
* tenant permissions with a strict `=== false`, so undefined would silently
|
|
245
|
+
* drop the permission this fixture grants and every case below would fail
|
|
246
|
+
* at the guard instead of exercising the handler.
|
|
247
|
+
*/
|
|
248
|
+
const userPermissions: Array<UserPermission> = [
|
|
249
|
+
Permission.ReadTelemetryException,
|
|
250
|
+
].map((permission: Permission): UserPermission => {
|
|
251
|
+
return {
|
|
252
|
+
_type: "UserPermission",
|
|
253
|
+
permission: permission,
|
|
254
|
+
labelIds: [],
|
|
255
|
+
isBlockPermission: false,
|
|
256
|
+
};
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
const tenantPermission: UserTenantAccessPermission = {
|
|
260
|
+
_type: "UserTenantAccessPermission",
|
|
261
|
+
projectId: data.projectId,
|
|
262
|
+
permissions: userPermissions,
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const permissionMap: Dictionary<UserTenantAccessPermission> = {};
|
|
266
|
+
permissionMap[data.projectId.toString()] = tenantPermission;
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
userType: UserType.User,
|
|
270
|
+
tenantId: data.projectId,
|
|
271
|
+
userTenantAccessPermission: permissionMap,
|
|
272
|
+
userAuthorization: { userId: data.userId },
|
|
273
|
+
} as unknown as JSONObject;
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
/*
|
|
277
|
+
* Well-formed frames. Every one is a distinct object so nothing about the
|
|
278
|
+
* cap can be an artifact of array element identity.
|
|
279
|
+
*/
|
|
280
|
+
type MakeFramesFunction = (count: number) => Array<JSONObject>;
|
|
281
|
+
|
|
282
|
+
const makeFrames: MakeFramesFunction = (count: number): Array<JSONObject> => {
|
|
283
|
+
return Array.from(
|
|
284
|
+
{ length: count },
|
|
285
|
+
(_unused: unknown, index: number): JSONObject => {
|
|
286
|
+
return {
|
|
287
|
+
functionName: `minified${index}`,
|
|
288
|
+
fileName: "https://app.example.com/assets/main.abc123.js",
|
|
289
|
+
lineNumber: 1,
|
|
290
|
+
columnNumber: index,
|
|
291
|
+
inApp: true,
|
|
292
|
+
};
|
|
293
|
+
},
|
|
294
|
+
);
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
/*
|
|
298
|
+
* Elements sanitize throws away entirely (null, primitives, nested arrays):
|
|
299
|
+
* a payload of these sanitizes to [] no matter how long it is, which is
|
|
300
|
+
* exactly the shape that has to be rejected on length rather than quietly
|
|
301
|
+
* accepted as an empty resolve.
|
|
302
|
+
*/
|
|
303
|
+
type MakeJunkFramesFunction = (count: number) => Array<unknown>;
|
|
304
|
+
|
|
305
|
+
const makeJunkFrames: MakeJunkFramesFunction = (
|
|
306
|
+
count: number,
|
|
307
|
+
): Array<unknown> => {
|
|
308
|
+
return Array.from({ length: count }, (_unused: unknown, index: number) => {
|
|
309
|
+
if (index % 3 === 0) {
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (index % 3 === 1) {
|
|
314
|
+
return "not-a-frame";
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return [index];
|
|
318
|
+
});
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const EMPTY_RESULT: ResolveStackTraceResult = {
|
|
322
|
+
frames: [],
|
|
323
|
+
resolvedCount: 0,
|
|
324
|
+
sourceMapCount: 0,
|
|
325
|
+
sourceMapsSkippedForSize: 0,
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const TOO_MANY_FRAMES_MESSAGE: string = `frames must contain at most ${MAX_FRAMES_PER_RESOLVE_REQUEST} stack frames.`;
|
|
329
|
+
const NOT_AN_ARRAY_MESSAGE: string = "frames must be an array of stack frames";
|
|
330
|
+
|
|
331
|
+
describe("POST /telemetry/exceptions/resolve-stack-trace frames cap", () => {
|
|
332
|
+
let projectId: ObjectID;
|
|
333
|
+
let userId: ObjectID;
|
|
334
|
+
let serviceId: ObjectID;
|
|
335
|
+
|
|
336
|
+
interface Spy {
|
|
337
|
+
mock: { calls: Array<Array<unknown>> };
|
|
338
|
+
mockResolvedValue: (value: ResolveStackTraceResult) => unknown;
|
|
339
|
+
mockRejectedValue: (value: unknown) => unknown;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
let resolveFramesForService: Spy;
|
|
343
|
+
let sanitizeMinifiedStackFrames: Spy;
|
|
344
|
+
|
|
345
|
+
beforeAll(() => {
|
|
346
|
+
recordedRoutes.length = 0;
|
|
347
|
+
/*
|
|
348
|
+
* Loaded lazily rather than with a top-level import: TelemetryAPI calls
|
|
349
|
+
* Express.getRouter() at module scope, so a static import would run the
|
|
350
|
+
* mock factory before `telemetryRouter` is initialised and die in the
|
|
351
|
+
* temporal dead zone.
|
|
352
|
+
*/
|
|
353
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
354
|
+
require("../../../Server/API/TelemetryAPI");
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
beforeEach(() => {
|
|
358
|
+
jest.clearAllMocks();
|
|
359
|
+
|
|
360
|
+
projectId = ObjectID.generate();
|
|
361
|
+
userId = ObjectID.generate();
|
|
362
|
+
serviceId = ObjectID.generate();
|
|
363
|
+
|
|
364
|
+
/*
|
|
365
|
+
* CI runs the Common suite with BILLING_ENABLED=true (see test-setup.sh),
|
|
366
|
+
* so getDatabaseCommonInteractionProps resolves the caller's plan through
|
|
367
|
+
* ProjectService.getCurrentPlan. These fixtures use a project that never
|
|
368
|
+
* exists in the database, so the real lookup throws and the handler's
|
|
369
|
+
* catch swallows the request before it reaches the frames guard. Billing
|
|
370
|
+
* is orthogonal to the cap, so stub the plan lookup and let the rest run.
|
|
371
|
+
*/
|
|
372
|
+
jest
|
|
373
|
+
.spyOn(ProjectService, "getCurrentPlan")
|
|
374
|
+
.mockResolvedValue({ plan: null, isSubscriptionUnpaid: false });
|
|
375
|
+
|
|
376
|
+
resolveFramesForService = jest.spyOn(
|
|
377
|
+
TelemetrySourceMapService,
|
|
378
|
+
"resolveFramesForService" as never,
|
|
379
|
+
) as unknown as Spy;
|
|
380
|
+
resolveFramesForService.mockResolvedValue(EMPTY_RESULT);
|
|
381
|
+
|
|
382
|
+
/*
|
|
383
|
+
* Spied, not stubbed: the real implementation still runs, so the cases
|
|
384
|
+
* that assert what the handler forwards are exercising real sanitize
|
|
385
|
+
* output while the call log proves whether sanitize ran at all.
|
|
386
|
+
*/
|
|
387
|
+
sanitizeMinifiedStackFrames = jest.spyOn(
|
|
388
|
+
SourceMapResolver,
|
|
389
|
+
"sanitizeMinifiedStackFrames" as never,
|
|
390
|
+
) as unknown as Spy;
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
afterEach(() => {
|
|
394
|
+
jest.restoreAllMocks();
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
type CallFunction = (body: unknown) => Promise<CallResult>;
|
|
398
|
+
|
|
399
|
+
const call: CallFunction = (body: unknown): Promise<CallResult> => {
|
|
400
|
+
return callRoute({
|
|
401
|
+
request: buildPrincipal({ projectId: projectId, userId: userId }),
|
|
402
|
+
body: body,
|
|
403
|
+
});
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
type BodyWithFramesFunction = (frames: unknown) => JSONObject;
|
|
407
|
+
|
|
408
|
+
const bodyWithFrames: BodyWithFramesFunction = (
|
|
409
|
+
frames: unknown,
|
|
410
|
+
): JSONObject => {
|
|
411
|
+
return {
|
|
412
|
+
serviceId: serviceId.toString(),
|
|
413
|
+
serviceVersion: "1.4.2",
|
|
414
|
+
frames: frames,
|
|
415
|
+
} as JSONObject;
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
type ForwardedFramesFunction = () => Array<MinifiedStackFrame>;
|
|
419
|
+
|
|
420
|
+
const forwardedFrames: ForwardedFramesFunction =
|
|
421
|
+
(): Array<MinifiedStackFrame> => {
|
|
422
|
+
const argument: JSONObject = resolveFramesForService.mock
|
|
423
|
+
.calls[0]![0] as JSONObject;
|
|
424
|
+
|
|
425
|
+
return argument["frames"] as unknown as Array<MinifiedStackFrame>;
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
describe("route registration", () => {
|
|
429
|
+
test("the route is registered as POST behind the exception-read guard chain", () => {
|
|
430
|
+
const route: RecordedRoute = findRoute(RESOLVE_ROUTE);
|
|
431
|
+
|
|
432
|
+
expect(route.uri).toBe(RESOLVE_ROUTE);
|
|
433
|
+
// getUserMiddleware, requireUserAuthentication, requirePermission, handler.
|
|
434
|
+
expect(route.handlers).toHaveLength(4);
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
describe("the limit itself", () => {
|
|
439
|
+
test("MAX_FRAMES_PER_RESOLVE_REQUEST is 10000", () => {
|
|
440
|
+
expect(MAX_FRAMES_PER_RESOLVE_REQUEST).toBe(10000);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
/*
|
|
444
|
+
* The two bounds do different jobs and must not be confused for each
|
|
445
|
+
* other: MAX_FRAMES_TO_RESOLVE is how many frames get *resolved* against
|
|
446
|
+
* a map, this one is how many a caller may *submit*. If the request cap
|
|
447
|
+
* ever slid down to the resolve cap, browsers that send deep async traces
|
|
448
|
+
* would start getting 400s instead of a partially-resolved trace, so the
|
|
449
|
+
* gap between them is deliberate and worth pinning.
|
|
450
|
+
*/
|
|
451
|
+
test("the request cap sits far above the per-request resolve cap", () => {
|
|
452
|
+
expect(MAX_FRAMES_PER_RESOLVE_REQUEST).toBeGreaterThan(
|
|
453
|
+
MAX_FRAMES_TO_RESOLVE,
|
|
454
|
+
);
|
|
455
|
+
expect(MAX_FRAMES_PER_RESOLVE_REQUEST).toBeGreaterThanOrEqual(
|
|
456
|
+
MAX_FRAMES_TO_RESOLVE * 10,
|
|
457
|
+
);
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
describe("accepted sizes", () => {
|
|
462
|
+
test("a single frame resolves", async () => {
|
|
463
|
+
const result: CallResult = await call(bodyWithFrames(makeFrames(1)));
|
|
464
|
+
|
|
465
|
+
expect(result.deniedWith).toBeUndefined();
|
|
466
|
+
expect(resolveFramesForService.mock.calls).toHaveLength(1);
|
|
467
|
+
expect(forwardedFrames()).toHaveLength(1);
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
test("one frame under the cap is accepted", async () => {
|
|
471
|
+
const result: CallResult = await call(
|
|
472
|
+
bodyWithFrames(makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST - 1)),
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
expect(result.deniedWith).toBeUndefined();
|
|
476
|
+
expect(resolveFramesForService.mock.calls).toHaveLength(1);
|
|
477
|
+
expect(forwardedFrames()).toHaveLength(
|
|
478
|
+
MAX_FRAMES_PER_RESOLVE_REQUEST - 1,
|
|
479
|
+
);
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
/*
|
|
483
|
+
* The boundary. The guard is a `>` comparison, so a trace of exactly the
|
|
484
|
+
* cap is a legal request; an off-by-one here would reject the very
|
|
485
|
+
* payload the constant advertises as the maximum.
|
|
486
|
+
*/
|
|
487
|
+
test("exactly MAX_FRAMES_PER_RESOLVE_REQUEST frames is accepted, not rejected by the cap", async () => {
|
|
488
|
+
const result: CallResult = await call(
|
|
489
|
+
bodyWithFrames(makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST)),
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
expect(result.deniedWith).toBeUndefined();
|
|
493
|
+
expect(result.thrownToNext).toBeUndefined();
|
|
494
|
+
expect(resolveFramesForService.mock.calls).toHaveLength(1);
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
/*
|
|
498
|
+
* And it is accepted in full. sanitize does not truncate, and the handler
|
|
499
|
+
* does not either — which is precisely why the cap has to exist at this
|
|
500
|
+
* layer rather than being left to a downstream slice.
|
|
501
|
+
*/
|
|
502
|
+
test("an at-cap request forwards all 10000 frames — nothing truncates on the way through", async () => {
|
|
503
|
+
await call(bodyWithFrames(makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST)));
|
|
504
|
+
|
|
505
|
+
expect(forwardedFrames()).toHaveLength(MAX_FRAMES_PER_RESOLVE_REQUEST);
|
|
506
|
+
expect(forwardedFrames()).not.toHaveLength(MAX_FRAMES_TO_RESOLVE);
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
test("an empty frames array is accepted — the cap only bounds the top end", async () => {
|
|
510
|
+
const result: CallResult = await call(bodyWithFrames([]));
|
|
511
|
+
|
|
512
|
+
expect(result.deniedWith).toBeUndefined();
|
|
513
|
+
expect(resolveFramesForService.mock.calls).toHaveLength(1);
|
|
514
|
+
expect(forwardedFrames()).toHaveLength(0);
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
test("an accepted request returns the resolver's result to the caller", async () => {
|
|
518
|
+
const resolved: ResolveStackTraceResult = {
|
|
519
|
+
frames: [],
|
|
520
|
+
resolvedCount: 3,
|
|
521
|
+
sourceMapCount: 2,
|
|
522
|
+
sourceMapsSkippedForSize: 1,
|
|
523
|
+
};
|
|
524
|
+
resolveFramesForService.mockResolvedValue(resolved);
|
|
525
|
+
|
|
526
|
+
const result: CallResult = await call(
|
|
527
|
+
bodyWithFrames(makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST)),
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
expect(result.jsonBody).toMatchObject({
|
|
531
|
+
resolvedCount: 3,
|
|
532
|
+
sourceMapCount: 2,
|
|
533
|
+
sourceMapsSkippedForSize: 1,
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
test("the accepted request is scoped to the caller's tenant and body service", async () => {
|
|
538
|
+
await call(bodyWithFrames(makeFrames(10)));
|
|
539
|
+
|
|
540
|
+
const argument: JSONObject = resolveFramesForService.mock
|
|
541
|
+
.calls[0]![0] as JSONObject;
|
|
542
|
+
|
|
543
|
+
expect((argument["projectId"] as ObjectID).toString()).toBe(
|
|
544
|
+
projectId.toString(),
|
|
545
|
+
);
|
|
546
|
+
expect((argument["serviceId"] as ObjectID).toString()).toBe(
|
|
547
|
+
serviceId.toString(),
|
|
548
|
+
);
|
|
549
|
+
expect(argument["serviceVersion"]).toBe("1.4.2");
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
describe("rejected sizes", () => {
|
|
554
|
+
/*
|
|
555
|
+
* One over the boundary. This is the case the cap exists for, and the
|
|
556
|
+
* only place the off-by-one can be caught from the outside.
|
|
557
|
+
*/
|
|
558
|
+
test("one frame over the cap is rejected with a BadDataException", async () => {
|
|
559
|
+
const result: CallResult = await call(
|
|
560
|
+
bodyWithFrames(makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST + 1)),
|
|
561
|
+
);
|
|
562
|
+
|
|
563
|
+
expect(result.deniedWith).toBeInstanceOf(BadDataException);
|
|
564
|
+
expect(resolveFramesForService.mock.calls).toHaveLength(0);
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
/*
|
|
568
|
+
* The message has to name the limit: the caller is a build tool or a
|
|
569
|
+
* browser SDK batching frames, and "too many frames" without the number
|
|
570
|
+
* gives it nothing to clamp to.
|
|
571
|
+
*/
|
|
572
|
+
test("the rejection message names the limit", async () => {
|
|
573
|
+
const result: CallResult = await call(
|
|
574
|
+
bodyWithFrames(makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST + 1)),
|
|
575
|
+
);
|
|
576
|
+
|
|
577
|
+
expect(result.deniedWith?.message).toBe(TOO_MANY_FRAMES_MESSAGE);
|
|
578
|
+
expect(result.deniedWith?.message).toContain(
|
|
579
|
+
String(MAX_FRAMES_PER_RESOLVE_REQUEST),
|
|
580
|
+
);
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
test("a wildly oversized array is rejected the same way, not merely trimmed", async () => {
|
|
584
|
+
const result: CallResult = await call(
|
|
585
|
+
bodyWithFrames(makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST * 2)),
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
expect(result.deniedWith).toBeInstanceOf(BadDataException);
|
|
589
|
+
expect(result.deniedWith?.message).toBe(TOO_MANY_FRAMES_MESSAGE);
|
|
590
|
+
expect(resolveFramesForService.mock.calls).toHaveLength(0);
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
test("no response body is produced for a rejected request", async () => {
|
|
594
|
+
const result: CallResult = await call(
|
|
595
|
+
bodyWithFrames(makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST + 1)),
|
|
596
|
+
);
|
|
597
|
+
|
|
598
|
+
expect(result.jsonBody).toBeUndefined();
|
|
599
|
+
expect(result.thrownToNext).toBeUndefined();
|
|
600
|
+
});
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
describe("guard ordering: the cap runs AFTER the Array.isArray check", () => {
|
|
604
|
+
/*
|
|
605
|
+
* A non-array `frames` must keep its own precise error. If the length
|
|
606
|
+
* check were hoisted above the type check it would read `.length` off
|
|
607
|
+
* whatever the caller sent — and a string, or any array-like object,
|
|
608
|
+
* has a length — so a plainly malformed body would come back complaining
|
|
609
|
+
* about a limit it never approached.
|
|
610
|
+
*/
|
|
611
|
+
test("a non-array frames value gets the array error, not the length error", async () => {
|
|
612
|
+
const result: CallResult = await call(bodyWithFrames({ zero: "frame" }));
|
|
613
|
+
|
|
614
|
+
expect(result.deniedWith).toBeInstanceOf(BadDataException);
|
|
615
|
+
expect(result.deniedWith?.message).toBe(NOT_AN_ARRAY_MESSAGE);
|
|
616
|
+
expect(resolveFramesForService.mock.calls).toHaveLength(0);
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
test("an array-like object longer than the cap still gets the array error", async () => {
|
|
620
|
+
const result: CallResult = await call(
|
|
621
|
+
bodyWithFrames({ length: MAX_FRAMES_PER_RESOLVE_REQUEST + 1 }),
|
|
622
|
+
);
|
|
623
|
+
|
|
624
|
+
expect(result.deniedWith?.message).toBe(NOT_AN_ARRAY_MESSAGE);
|
|
625
|
+
expect(result.deniedWith?.message).not.toBe(TOO_MANY_FRAMES_MESSAGE);
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
test("a string longer than the cap still gets the array error", async () => {
|
|
629
|
+
const result: CallResult = await call(
|
|
630
|
+
bodyWithFrames("f".repeat(MAX_FRAMES_PER_RESOLVE_REQUEST + 1)),
|
|
631
|
+
);
|
|
632
|
+
|
|
633
|
+
expect(result.deniedWith?.message).toBe(NOT_AN_ARRAY_MESSAGE);
|
|
634
|
+
expect(result.deniedWith?.message).not.toBe(TOO_MANY_FRAMES_MESSAGE);
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
test("a missing frames field gets the array error", async () => {
|
|
638
|
+
const result: CallResult = await call({
|
|
639
|
+
serviceId: serviceId.toString(),
|
|
640
|
+
serviceVersion: "1.4.2",
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
expect(result.deniedWith?.message).toBe(NOT_AN_ARRAY_MESSAGE);
|
|
644
|
+
expect(resolveFramesForService.mock.calls).toHaveLength(0);
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
test("a null frames field gets the array error", async () => {
|
|
648
|
+
const result: CallResult = await call(bodyWithFrames(null));
|
|
649
|
+
|
|
650
|
+
expect(result.deniedWith?.message).toBe(NOT_AN_ARRAY_MESSAGE);
|
|
651
|
+
});
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
describe("guard ordering: the cap runs BEFORE sanitize", () => {
|
|
655
|
+
/*
|
|
656
|
+
* The regression this ordering fixes. sanitize walks every element and
|
|
657
|
+
* silently drops the ones that are not objects, so an oversized array of
|
|
658
|
+
* pure junk sanitizes to [] — and a cap placed after sanitize would see
|
|
659
|
+
* a length of 0, wave the request through, and only then have done the
|
|
660
|
+
* per-element work the cap was supposed to prevent. The caller would get
|
|
661
|
+
* a cheerful empty resolve for a payload the server should have refused.
|
|
662
|
+
*/
|
|
663
|
+
test("an oversized array of junk is rejected on length, not silently sanitized to []", async () => {
|
|
664
|
+
const result: CallResult = await call(
|
|
665
|
+
bodyWithFrames(makeJunkFrames(MAX_FRAMES_PER_RESOLVE_REQUEST + 1)),
|
|
666
|
+
);
|
|
667
|
+
|
|
668
|
+
expect(result.deniedWith).toBeInstanceOf(BadDataException);
|
|
669
|
+
expect(result.deniedWith?.message).toBe(TOO_MANY_FRAMES_MESSAGE);
|
|
670
|
+
expect(resolveFramesForService.mock.calls).toHaveLength(0);
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
test("sanitize is never invoked for an oversized array", async () => {
|
|
674
|
+
await call(
|
|
675
|
+
bodyWithFrames(makeJunkFrames(MAX_FRAMES_PER_RESOLVE_REQUEST + 1)),
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
expect(sanitizeMinifiedStackFrames.mock.calls).toHaveLength(0);
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
test("sanitize is never invoked for an oversized array of well-formed frames either", async () => {
|
|
682
|
+
await call(
|
|
683
|
+
bodyWithFrames(makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST + 1)),
|
|
684
|
+
);
|
|
685
|
+
|
|
686
|
+
expect(sanitizeMinifiedStackFrames.mock.calls).toHaveLength(0);
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
/*
|
|
690
|
+
* The other half of the ordering: under the cap, sanitize still runs and
|
|
691
|
+
* still does its filtering. The guard bounds the work; it does not
|
|
692
|
+
* replace the type coercion.
|
|
693
|
+
*/
|
|
694
|
+
test("an under-cap array of junk does reach sanitize and comes out empty", async () => {
|
|
695
|
+
const result: CallResult = await call(
|
|
696
|
+
bodyWithFrames(makeJunkFrames(MAX_FRAMES_PER_RESOLVE_REQUEST)),
|
|
697
|
+
);
|
|
698
|
+
|
|
699
|
+
expect(result.deniedWith).toBeUndefined();
|
|
700
|
+
expect(sanitizeMinifiedStackFrames.mock.calls).toHaveLength(1);
|
|
701
|
+
expect(forwardedFrames()).toHaveLength(0);
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
test("an at-cap mixed array forwards only the object frames sanitize kept", async () => {
|
|
705
|
+
const mixed: Array<unknown> = [
|
|
706
|
+
...makeFrames(4),
|
|
707
|
+
...makeJunkFrames(MAX_FRAMES_PER_RESOLVE_REQUEST - 4),
|
|
708
|
+
];
|
|
709
|
+
|
|
710
|
+
const result: CallResult = await call(bodyWithFrames(mixed));
|
|
711
|
+
|
|
712
|
+
expect(result.deniedWith).toBeUndefined();
|
|
713
|
+
expect(forwardedFrames()).toHaveLength(4);
|
|
714
|
+
});
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
describe("guard ordering: serviceId and serviceVersion are checked first", () => {
|
|
718
|
+
/*
|
|
719
|
+
* The identity checks stay in front of the cap. A request that is both
|
|
720
|
+
* oversized and missing its serviceId is not a limits problem — telling
|
|
721
|
+
* the caller about the frame limit would send them off trimming a trace
|
|
722
|
+
* when the actual defect is an unset field, and they would hit the same
|
|
723
|
+
* wall again with a shorter payload.
|
|
724
|
+
*/
|
|
725
|
+
test("an oversized request missing serviceId is refused for serviceId", async () => {
|
|
726
|
+
const result: CallResult = await call({
|
|
727
|
+
serviceVersion: "1.4.2",
|
|
728
|
+
frames: makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST + 1),
|
|
729
|
+
} as unknown as JSONObject);
|
|
730
|
+
|
|
731
|
+
expect(result.deniedWith?.message).toBe("serviceId is required");
|
|
732
|
+
expect(result.deniedWith?.message).not.toBe(TOO_MANY_FRAMES_MESSAGE);
|
|
733
|
+
expect(resolveFramesForService.mock.calls).toHaveLength(0);
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
test("an oversized request with a non-string serviceId is refused for serviceId", async () => {
|
|
737
|
+
const result: CallResult = await call({
|
|
738
|
+
serviceId: 42,
|
|
739
|
+
serviceVersion: "1.4.2",
|
|
740
|
+
frames: makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST + 1),
|
|
741
|
+
} as unknown as JSONObject);
|
|
742
|
+
|
|
743
|
+
expect(result.deniedWith?.message).toBe("serviceId is required");
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
test("an oversized request missing serviceVersion is refused for serviceVersion", async () => {
|
|
747
|
+
const result: CallResult = await call({
|
|
748
|
+
serviceId: serviceId.toString(),
|
|
749
|
+
frames: makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST + 1),
|
|
750
|
+
} as unknown as JSONObject);
|
|
751
|
+
|
|
752
|
+
expect(result.deniedWith?.message).toBe("serviceVersion is required");
|
|
753
|
+
expect(result.deniedWith?.message).not.toBe(TOO_MANY_FRAMES_MESSAGE);
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
/*
|
|
757
|
+
* And the tenant check stays in front of everything: an unscoped request
|
|
758
|
+
* must never get as far as reporting anything about its payload.
|
|
759
|
+
*/
|
|
760
|
+
test("an oversized request without a tenant is refused for the project, not the frames", async () => {
|
|
761
|
+
jest
|
|
762
|
+
.spyOn(CommonAPI, "getDatabaseCommonInteractionProps")
|
|
763
|
+
.mockResolvedValue({
|
|
764
|
+
tenantId: undefined,
|
|
765
|
+
userType: UserType.User,
|
|
766
|
+
} as unknown as DatabaseCommonInteractionProps);
|
|
767
|
+
|
|
768
|
+
const result: CallResult = await call(
|
|
769
|
+
bodyWithFrames(makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST + 1)),
|
|
770
|
+
);
|
|
771
|
+
|
|
772
|
+
expect(result.deniedWith?.message).toBe("Invalid Project ID");
|
|
773
|
+
expect(resolveFramesForService.mock.calls).toHaveLength(0);
|
|
774
|
+
});
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
describe("the cap is a request guard, not an error handler", () => {
|
|
778
|
+
/*
|
|
779
|
+
* A rejected request answers the caller directly; it must not fall
|
|
780
|
+
* through to express' error path, which would turn a 400 into a 500.
|
|
781
|
+
*/
|
|
782
|
+
test("an oversized request is answered, not thrown to next", async () => {
|
|
783
|
+
const result: CallResult = await call(
|
|
784
|
+
bodyWithFrames(makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST + 1)),
|
|
785
|
+
);
|
|
786
|
+
|
|
787
|
+
expect(result.thrownToNext).toBeUndefined();
|
|
788
|
+
expect(result.deniedWith).toBeDefined();
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
// A failure below the guard still goes to next, as it always did.
|
|
792
|
+
test("a resolver failure on an accepted request still reaches the error handler", async () => {
|
|
793
|
+
resolveFramesForService.mockRejectedValue(
|
|
794
|
+
new Error("clickhouse said no"),
|
|
795
|
+
);
|
|
796
|
+
|
|
797
|
+
const result: CallResult = await call(
|
|
798
|
+
bodyWithFrames(makeFrames(MAX_FRAMES_PER_RESOLVE_REQUEST)),
|
|
799
|
+
);
|
|
800
|
+
|
|
801
|
+
expect(result.thrownToNext).toBeDefined();
|
|
802
|
+
expect(result.jsonBody).toBeUndefined();
|
|
803
|
+
});
|
|
804
|
+
});
|
|
805
|
+
});
|