@oneuptime/common 13.0.7 → 13.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +1 -1
- package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +1 -1
- package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +1 -1
- package/Server/API/AIBillingAPI.ts +1 -0
- package/Server/API/AIInsightAPI.ts +1 -4
- package/Server/API/AIInvestigationAPI.ts +1 -4
- package/Server/API/AIReadinessAPI.ts +4 -5
- package/Server/API/AlertAPI.ts +1 -0
- package/Server/API/AutoRemediationAPI.ts +1 -4
- package/Server/API/BaseAPI.ts +13 -0
- package/Server/API/BaseAnalyticsAPI.ts +80 -9
- package/Server/API/BillingAPI.ts +2 -0
- package/Server/API/BillingInvoiceAPI.ts +1 -0
- package/Server/API/BillingPaymentMethodAPI.ts +2 -0
- package/Server/API/CodeFixRunAPI.ts +1 -3
- package/Server/API/CommonAPI.ts +68 -4
- package/Server/API/DashboardAPI.ts +12 -12
- package/Server/API/GlobalConfigAPI.ts +17 -0
- package/Server/API/IncidentAPI.ts +2 -0
- package/Server/API/IncidentEpisodeAPI.ts +1 -0
- package/Server/API/NotificationAPI.ts +1 -0
- package/Server/API/OnCallCalendarAPI.ts +4 -5
- package/Server/API/OnCallDutyPolicyAPI.ts +7 -0
- package/Server/API/OnCallReadinessAPI.ts +4 -1
- package/Server/API/OnCallScheduleTimelineAPI.ts +731 -0
- package/Server/API/ProjectAPI.ts +1 -0
- package/Server/API/ScheduledMaintenanceAPI.ts +1 -0
- package/Server/API/StatusPageAPI.ts +161 -32
- package/Server/API/TeamMemberAPI.ts +3 -0
- package/Server/API/UserCallAPI.ts +2 -0
- package/Server/API/UserEmailAPI.ts +2 -0
- package/Server/API/UserIncomingCallNumberAPI.ts +2 -0
- package/Server/API/UserMicrosoftTeamsAPI.ts +1 -0
- package/Server/API/UserSlackAPI.ts +1 -0
- package/Server/API/UserSmsAPI.ts +2 -0
- package/Server/API/UserTotpAuthAPI.ts +1 -0
- package/Server/API/UserWebAuthnAPI.ts +2 -0
- package/Server/API/UserWebhookAPI.ts +1 -0
- package/Server/API/UserWhatsAppAPI.ts +2 -0
- package/Server/Middleware/MasterAdminAuthorization.ts +13 -2
- package/Server/Middleware/UserAuthorization.ts +79 -5
- package/Server/Services/ApiKeyPermissionService.ts +101 -4
- package/Server/Services/DatabaseService.ts +245 -0
- package/Server/Services/DetectionRuleService.ts +5 -4
- package/Server/Services/OnCallDutyPolicyChildService.ts +261 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +2 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -2
- package/Server/Services/PayAsYouGoBillingService.ts +23 -28
- package/Server/Services/ProjectService.ts +18 -0
- package/Server/Services/RumSessionPinService.ts +274 -22
- package/Server/Services/TeamPermissionService.ts +120 -26
- package/Server/Services/ThreatIntelFeedService.ts +6 -3
- package/Server/Types/Database/Permissions/BasePermission.ts +9 -7
- package/Server/Types/Database/Permissions/Index.ts +75 -11
- package/Server/Types/Database/Permissions/TablePermission.ts +24 -28
- package/Server/Utils/AI/AIChatPrivacyFilter.ts +8 -0
- package/Server/Utils/AI/AIRunPrivacyFilter.ts +8 -0
- package/Server/Utils/MasterAdminPageAccess.ts +61 -0
- package/Server/Utils/Monitor/MonitorAlert.ts +3 -1
- package/Server/Utils/Monitor/MonitorIncident.ts +3 -1
- package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1 -1
- package/Server/Utils/Realtime.ts +163 -45
- package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +11 -28
- package/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.ts +170 -0
- package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +1 -1
- package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.ts +6 -2
- package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.ts +10 -9
- package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +1059 -0
- package/Tests/App/Dashboard/AffectedResourcesPickerEditForm.test.tsx +376 -0
- package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +757 -0
- package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +307 -0
- package/Tests/App/Dashboard/ArgumentsFormGroupByUnlistedAttributes.test.tsx +131 -0
- package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +1 -1
- package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +9 -1
- package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +24 -0
- package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +162 -8
- package/Tests/App/Dashboard/EntityFilterDropdownArchivedSlos.test.tsx +105 -6
- package/Tests/App/Dashboard/EntityFilterDropdownUnlistedSelection.test.tsx +434 -0
- package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +276 -1
- package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +9 -1
- package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +58 -42
- package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +42 -5
- package/Tests/App/Dashboard/ResourceAuditLogsSideMenus.test.tsx +34 -23
- package/Tests/App/Dashboard/ScheduleTimeline.test.tsx +1580 -0
- package/Tests/App/Dashboard/ScheduleTimelineAPI.test.ts +280 -0
- package/Tests/App/Dashboard/ScheduleTimelineModel.test.ts +673 -0
- package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +95 -68
- package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +86 -3
- package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +28 -3
- package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +761 -0
- package/Tests/App/Dashboard/SecurityEventsGuideContent.test.ts +1313 -0
- package/Tests/App/Dashboard/SecurityEventsHowItWorksCard.test.tsx +536 -0
- package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +222 -0
- package/Tests/App/Dashboard/SecurityEventsThreatIntelPage.test.tsx +199 -0
- package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +321 -0
- package/Tests/App/Dashboard/SloOverviewHero.test.tsx +171 -36
- package/Tests/App/Dashboard/SloViewSideMenu.test.tsx +215 -0
- package/Tests/App/Dashboard/SloViewSideMenuCounts.test.tsx +40 -3
- package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +12 -4
- package/Tests/App/PublicDashboard/PublicDashboardWidgetListAuth.test.tsx +623 -0
- package/Tests/Models/OnCallCalendarFeedModels.test.ts +23 -1
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +138 -5
- package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +187 -0
- package/Tests/Server/API/AIInvestigationAvailabilityAuthorization.test.ts +51 -3
- package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +55 -2
- package/Tests/Server/API/BaseAnalyticsAPIAggregateCache.test.ts +729 -0
- package/Tests/Server/API/BillingPayAsYouGoStatus.test.ts +93 -7
- package/Tests/Server/API/BillingPaymentMethodAPI.test.ts +36 -3
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +1003 -24
- package/Tests/Server/API/DashboardPublicRateLimit.test.ts +6 -3
- package/Tests/Server/API/ExpiredSessionAIRoutes.test.ts +708 -0
- package/Tests/Server/API/ExpiredSessionCustomRoutes.test.ts +928 -0
- package/Tests/Server/API/ExpiredSessionMonitorTemplate.test.ts +319 -0
- package/Tests/Server/API/ExpiredSessionOnCallDutyPolicy.test.ts +336 -0
- package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +820 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +140 -0
- package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +115 -12
- package/Tests/Server/API/OnCallCalendarAPI.test.ts +375 -8
- package/Tests/Server/API/OnCallReadinessAPI.test.ts +175 -17
- package/Tests/Server/API/OnCallScheduleTimelineAPI.test.ts +1513 -0
- package/Tests/Server/API/OnCallSetupReminderAPI.test.ts +119 -7
- package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +111 -4
- package/Tests/Server/API/PublicRouteInvalidAccessToken.test.ts +615 -0
- package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +89 -2
- package/Tests/Server/API/SessionReplayAPI.test.ts +121 -0
- package/Tests/Server/API/StatusPageMasterPasswordRateLimit.test.ts +4 -2
- package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +441 -0
- package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +664 -0
- package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +7 -0
- package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +6 -0
- package/Tests/Server/API/UserNotificationSettingAPI.test.ts +65 -4
- package/Tests/Server/API/UserProjectsAPI.test.ts +63 -3
- package/Tests/Server/API/UserTotpAuthAPI.test.ts +48 -2
- package/Tests/Server/API/UserWebAuthnAuthenticationOptionsRoute.test.ts +11 -2
- package/Tests/Server/API/UserWebAuthnBackupCodeMinting.test.ts +46 -3
- package/Tests/Server/API/UserWebAuthnPasskeyAPI.test.ts +18 -2
- package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +24 -7
- package/Tests/Server/Middleware/ExpiredSessionUserMiddleware.test.ts +563 -0
- package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +299 -19
- package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +453 -0
- package/Tests/Server/Services/AIChatPrivacyPin.test.ts +24 -0
- package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +2 -0
- package/Tests/Server/Services/ApiKeyPermissionService.test.ts +3 -3
- package/Tests/Server/Services/DatabaseServiceCreateSuppliedId.test.ts +147 -0
- package/Tests/Server/Services/DatabaseServiceLoginBeforeHooks.test.ts +1078 -0
- package/Tests/Server/Services/DatabaseServiceTenantRelationGuard.test.ts +259 -0
- package/Tests/Server/Services/DatabaseServiceWriteOperatorValues.test.ts +147 -0
- package/Tests/Server/Services/MonitorPayAsYouGoBilling.test.ts +115 -1
- package/Tests/Server/Services/OnCallChildCreateAuthorizationPostgres.test.ts +711 -0
- package/Tests/Server/Services/OnCallDutyPolicyChildService.test.ts +733 -0
- package/Tests/Server/Services/PayAsYouGoBillingService.test.ts +190 -140
- package/Tests/Server/Services/PayAsYouGoStripeRateLimitBudget.test.ts +4 -9
- package/Tests/Server/Services/PermissionBlockDeletion.test.ts +780 -0
- package/Tests/Server/Services/PermissionBlockDeletionPostgres.test.ts +628 -0
- package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +77 -1
- package/Tests/Server/Services/RumSessionPinCreatePermission.test.ts +715 -0
- package/Tests/Server/Services/TeamMemberMultiTenantReadPostgres.test.ts +394 -0
- package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +6 -0
- package/Tests/Server/Services/TelemetryPayAsYouGoBilling.test.ts +131 -0
- package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +13 -2
- package/Tests/Server/Types/Database/Permissions/ModelPermissionAnonymousRefusal.test.ts +518 -0
- package/Tests/Server/Types/Database/Permissions/MultiTenantPermissions.test.ts +350 -0
- package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +282 -25
- package/Tests/Server/Types/Database/Permissions/TableLevelBlockPermission.test.ts +459 -0
- package/Tests/Server/Utils/AI/AIRunPrivacyFilter.test.ts +101 -9
- package/Tests/Server/Utils/AI/ChatAgentHelpers.test.ts +88 -4
- package/Tests/Server/Utils/AI/Toolbox/ExceptionTools.test.ts +459 -0
- package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +794 -0
- package/Tests/Server/Utils/AI/Toolbox/RecentChangesTools.test.ts +574 -0
- package/Tests/Server/Utils/AI/Toolbox/SecurityEventTools.test.ts +596 -0
- package/Tests/Server/Utils/CaptchaRequestAndLogging.test.ts +395 -0
- package/Tests/Server/Utils/MasterAdminPageAccess.test.ts +251 -0
- package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +616 -0
- package/Tests/Server/Utils/Realtime.test.ts +502 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorSeverity.test.ts +216 -0
- package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +142 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.test.ts +140 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepairClickhouseIntegration.test.ts +542 -0
- package/Tests/Server/Utils/Telemetry/ChangeEventRow.test.ts +743 -0
- package/Tests/Server/Utils/Telemetry/RuntimeMetrics.test.ts +465 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.test.ts +202 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.test.ts +231 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/Alert.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/AlertEpisode.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/Incident.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.test.ts +247 -0
- package/Tests/Types/AI/AIInsightEvidence.test.ts +206 -0
- package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtilAnonymous.test.ts +144 -0
- package/Tests/Types/Call/CallProvider.test.ts +528 -0
- package/Tests/Types/Kubernetes/KubernetesCostIngest.test.ts +236 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleTimeline.test.ts +736 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleTimelineLayout.test.ts +996 -0
- package/Tests/Types/SecurityEvent/SigmaRule.test.ts +142 -0
- package/Tests/Types/Workflow/Components/JSON.test.ts +182 -0
- package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +116 -1
- package/Tests/UI/Components/Dropdown/DropdownAsyncOptions.test.tsx +81 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +89 -1
- package/Tests/UI/Components/EventAttachmentList.test.tsx +174 -0
- package/Tests/UI/Components/Forms/BasicFormBurnRateTemplateDefaults.test.tsx +395 -0
- package/Tests/UI/Components/Forms/BasicFormCollapsibleSections.test.tsx +286 -0
- package/Tests/UI/Components/Forms/FormSummary.test.tsx +128 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableQueryChange.test.tsx +365 -0
- package/Tests/UI/Components/OpenAuthenticatedUrl.test.ts +358 -0
- package/Tests/UI/Components/SessionAwareImage.test.tsx +496 -0
- package/Tests/UI/Components/TelemetryHistogramZeroBuckets.test.tsx +190 -0
- package/Tests/UI/Components/TooltipInteractive.test.tsx +97 -0
- package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardInstallGuidance.test.tsx +1 -1
- package/Tests/UI/Monitor/EvaluationLogListTimestamps.test.tsx +367 -0
- package/Tests/UI/Utils/API/BaseAPIRefreshSession.test.ts +1087 -0
- package/Tests/UI/Utils/API/DashboardHost.ts +12 -0
- package/Tests/UI/Utils/API/FakeAxiosServer.ts +183 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
- package/Tests/UI/Utils/Cookie.test.ts +440 -0
- package/Tests/UI/Utils/ModelAPIRequestClient.test.ts +278 -0
- package/Tests/UI/Utils/Navigation.test.ts +33 -0
- package/Tests/UI/Utils/PricingPlan.test.ts +295 -0
- package/Tests/UI/Utils/Realtime.test.ts +759 -0
- package/Tests/UI/Utils/Telemetry/Telemetry.test.ts +500 -0
- package/Tests/Utils/APIInstanceDispatch.test.ts +311 -0
- package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizerSeverity.test.ts +565 -0
- package/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.ts +40 -0
- package/Types/Monitor/MonitorEvaluationSummary.ts +3 -0
- package/Types/OnCallDutyPolicy/ScheduleTimeline.ts +507 -0
- package/Types/OnCallDutyPolicy/ScheduleTimelineLayout.ts +589 -0
- package/Types/Realtime/EventName.ts +11 -0
- package/Types/SecurityEvent/DetectionFindingConstants.ts +14 -0
- package/Types/SecurityEvent/OcsfSeverity.ts +31 -26
- package/Types/SecurityEvent/SigmaRule.ts +51 -0
- package/Types/SecurityEvent/ThreatIntelConstants.ts +18 -0
- package/UI/Components/AttachmentList/EventAttachmentList.tsx +30 -2
- package/UI/Components/Dashboard/DashboardVariableControl.tsx +12 -2
- package/UI/Components/Dropdown/Dropdown.tsx +6 -1
- package/UI/Components/EditionLabel/EditionLabel.tsx +12 -0
- package/UI/Components/EventItem/EventItem.tsx +12 -1
- package/UI/Components/Forms/BasicForm.tsx +151 -126
- package/UI/Components/Forms/CollapsibleFormSection.tsx +63 -0
- package/UI/Components/Forms/Fields/FormField.tsx +10 -4
- package/UI/Components/Forms/FormSummary.tsx +7 -0
- package/UI/Components/Forms/Types/Field.ts +10 -0
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +2 -1
- package/UI/Components/Markdown.tsx/SessionAwareImage.tsx +122 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +34 -5
- package/UI/Components/ModelTable/TableView.tsx +1 -1
- package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +8 -1
- package/UI/Components/Tooltip/Tooltip.tsx +8 -1
- package/UI/Utils/API/API.ts +173 -12
- package/UI/Utils/API/RequestOptions.ts +11 -0
- package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +31 -7
- package/UI/Utils/ModelAPI/ModelAPI.ts +30 -9
- package/UI/Utils/Navigation.ts +9 -0
- package/UI/Utils/OpenAuthenticatedUrl.ts +154 -0
- package/UI/Utils/Realtime.ts +176 -30
- package/Utils/API.ts +14 -5
- package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +157 -7
- package/Utils/SecurityEvent/Sigma/SigmaRuleParser.ts +9 -17
- package/Utils/Slo/SloBurnRateTemplate.ts +2 -2
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +1 -1
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -1
- package/build/dist/Server/API/AIBillingAPI.js +1 -1
- package/build/dist/Server/API/AIBillingAPI.js.map +1 -1
- package/build/dist/Server/API/AIInsightAPI.js +1 -4
- package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +1 -4
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/AIReadinessAPI.js +1 -3
- package/build/dist/Server/API/AIReadinessAPI.js.map +1 -1
- package/build/dist/Server/API/AlertAPI.js +1 -1
- package/build/dist/Server/API/AlertAPI.js.map +1 -1
- package/build/dist/Server/API/AutoRemediationAPI.js +1 -4
- package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +12 -0
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js +55 -10
- package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
- package/build/dist/Server/API/BillingAPI.js +2 -2
- package/build/dist/Server/API/BillingAPI.js.map +1 -1
- package/build/dist/Server/API/BillingInvoiceAPI.js +1 -1
- package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
- package/build/dist/Server/API/BillingPaymentMethodAPI.js +2 -2
- package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
- package/build/dist/Server/API/CodeFixRunAPI.js +1 -3
- package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +50 -5
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +12 -12
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +12 -0
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +2 -2
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
- package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
- package/build/dist/Server/API/NotificationAPI.js +1 -1
- package/build/dist/Server/API/NotificationAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallCalendarAPI.js +1 -4
- package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallDutyPolicyAPI.js +6 -0
- package/build/dist/Server/API/OnCallDutyPolicyAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallReadinessAPI.js +4 -1
- package/build/dist/Server/API/OnCallReadinessAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +494 -0
- package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -0
- package/build/dist/Server/API/ProjectAPI.js +1 -1
- package/build/dist/Server/API/ProjectAPI.js.map +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +125 -33
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TeamMemberAPI.js +3 -3
- package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
- package/build/dist/Server/API/UserCallAPI.js +2 -2
- package/build/dist/Server/API/UserCallAPI.js.map +1 -1
- package/build/dist/Server/API/UserEmailAPI.js +2 -2
- package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js +2 -2
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
- package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +1 -1
- package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/UserSlackAPI.js +1 -1
- package/build/dist/Server/API/UserSlackAPI.js.map +1 -1
- package/build/dist/Server/API/UserSmsAPI.js +2 -2
- package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
- package/build/dist/Server/API/UserTotpAuthAPI.js +1 -1
- package/build/dist/Server/API/UserTotpAuthAPI.js.map +1 -1
- package/build/dist/Server/API/UserWebAuthnAPI.js +2 -2
- package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -1
- package/build/dist/Server/API/UserWebhookAPI.js +1 -1
- package/build/dist/Server/API/UserWebhookAPI.js.map +1 -1
- package/build/dist/Server/API/UserWhatsAppAPI.js +2 -2
- package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
- package/build/dist/Server/Middleware/MasterAdminAuthorization.js +11 -2
- package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +64 -4
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js +80 -4
- package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +171 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DetectionRuleService.js +4 -4
- package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyChildService.js +170 -0
- package/build/dist/Server/Services/OnCallDutyPolicyChildService.js.map +1 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -2
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +2 -2
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -2
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -2
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
- package/build/dist/Server/Services/PayAsYouGoBillingService.js +20 -27
- package/build/dist/Server/Services/PayAsYouGoBillingService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +17 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionPinService.js +180 -16
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
- package/build/dist/Server/Services/TeamPermissionService.js +89 -27
- package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
- package/build/dist/Server/Services/ThreatIntelFeedService.js +5 -4
- package/build/dist/Server/Services/ThreatIntelFeedService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js +9 -6
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/Index.js +60 -6
- package/build/dist/Server/Types/Database/Permissions/Index.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js +14 -13
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
- package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js +7 -0
- package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js.map +1 -1
- package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js +7 -0
- package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js.map +1 -1
- package/build/dist/Server/Utils/MasterAdminPageAccess.js +39 -0
- package/build/dist/Server/Utils/MasterAdminPageAccess.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +3 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +3 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Realtime.js +126 -37
- package/build/dist/Server/Utils/Realtime.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +7 -25
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js +127 -0
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js +3 -2
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js +4 -8
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js.map +1 -1
- package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js +31 -1
- package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js +321 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js +372 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js.map +1 -0
- package/build/dist/Types/Realtime/EventName.js +10 -0
- package/build/dist/Types/Realtime/EventName.js.map +1 -1
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +11 -0
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
- package/build/dist/Types/SecurityEvent/OcsfSeverity.js +30 -25
- package/build/dist/Types/SecurityEvent/OcsfSeverity.js.map +1 -1
- package/build/dist/Types/SecurityEvent/SigmaRule.js +47 -0
- package/build/dist/Types/SecurityEvent/SigmaRule.js.map +1 -1
- package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js +14 -0
- package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js.map +1 -1
- package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js +9 -4
- package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js.map +1 -1
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +10 -2
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js +5 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +11 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
- package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +70 -64
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/CollapsibleFormSection.js +27 -0
- package/build/dist/UI/Components/Forms/CollapsibleFormSection.js.map +1 -0
- package/build/dist/UI/Components/Forms/Fields/FormField.js +10 -7
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Forms/FormSummary.js +7 -0
- package/build/dist/UI/Components/Forms/FormSummary.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +2 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js +84 -0
- package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +14 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
- package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js +2 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
- package/build/dist/UI/Utils/API/API.js +143 -19
- package/build/dist/UI/Utils/API/API.js.map +1 -1
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +21 -7
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +26 -9
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +8 -0
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/UI/Utils/OpenAuthenticatedUrl.js +92 -0
- package/build/dist/UI/Utils/OpenAuthenticatedUrl.js.map +1 -0
- package/build/dist/UI/Utils/Realtime.js +120 -15
- package/build/dist/UI/Utils/Realtime.js.map +1 -1
- package/build/dist/Utils/API.js +13 -5
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +123 -6
- package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
- package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js +4 -18
- package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js.map +1 -1
- package/build/dist/Utils/Slo/SloBurnRateTemplate.js +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
// Must stay the first import: the client's URLs are built from HOST on load.
|
|
2
|
+
import { DASHBOARD_ORIGIN } from "../../UI/Utils/API/DashboardHost";
|
|
3
|
+
import FakeAxiosServer, {
|
|
4
|
+
FakeTransport,
|
|
5
|
+
SentRequest,
|
|
6
|
+
settle,
|
|
7
|
+
} from "../../UI/Utils/API/FakeAxiosServer";
|
|
8
|
+
import React from "react";
|
|
9
|
+
import { cleanup, render, screen, waitFor } from "@testing-library/react";
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
11
|
+
import axios from "axios";
|
|
12
|
+
import PublicDashboardAPI from "../../../../App/FeatureSet/PublicDashboard/src/Utils/API";
|
|
13
|
+
import { PUBLIC_DASHBOARD_API_URL } from "../../../../App/FeatureSet/PublicDashboard/src/Utils/Config";
|
|
14
|
+
import PublicDashboardUtil from "../../../../App/FeatureSet/PublicDashboard/src/Utils/PublicDashboard";
|
|
15
|
+
import PublicDashboardWidgetContext from "../../../../App/FeatureSet/PublicDashboard/src/Utils/WidgetContext";
|
|
16
|
+
import { DashboardBaseComponentProps } from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Components/DashboardBaseComponent";
|
|
17
|
+
import DashboardIncidentListComponentElement from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Components/DashboardIncidentListComponent";
|
|
18
|
+
import DashboardLogStreamComponentElement from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Components/DashboardLogStreamComponent";
|
|
19
|
+
import DashboardResourceList from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Utils/DashboardResourceList";
|
|
20
|
+
import {
|
|
21
|
+
getPublicDashboardContext,
|
|
22
|
+
PublicDashboardContext,
|
|
23
|
+
setPublicDashboardContext,
|
|
24
|
+
} from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Utils/PublicDashboardContext";
|
|
25
|
+
import SloWidgetData from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Utils/SloWidgetData";
|
|
26
|
+
import Log from "../../../Models/AnalyticsModels/Log";
|
|
27
|
+
import Incident from "../../../Models/DatabaseModels/Incident";
|
|
28
|
+
import HTTPErrorResponse from "../../../Types/API/HTTPErrorResponse";
|
|
29
|
+
import HTTPMethod from "../../../Types/API/HTTPMethod";
|
|
30
|
+
import HTTPResponse from "../../../Types/API/HTTPResponse";
|
|
31
|
+
import Route from "../../../Types/API/Route";
|
|
32
|
+
import URL from "../../../Types/API/URL";
|
|
33
|
+
import InBetween from "../../../Types/BaseDatabase/InBetween";
|
|
34
|
+
import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
|
|
35
|
+
import DashboardIncidentListComponent from "../../../Types/Dashboard/DashboardComponents/DashboardIncidentListComponent";
|
|
36
|
+
import DashboardLogStreamComponent from "../../../Types/Dashboard/DashboardComponents/DashboardLogStreamComponent";
|
|
37
|
+
import { JSONObject, ObjectType } from "../../../Types/JSON";
|
|
38
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
39
|
+
import TimeRange from "../../../Types/Time/TimeRange";
|
|
40
|
+
import { SLO_WIDGET_NAME_MATCH_LIMIT } from "../../../Utils/Dashboard/SloWidgetSource";
|
|
41
|
+
import { IDENTITY_URL } from "../../../UI/Config";
|
|
42
|
+
import AnalyticsModelAPI from "../../../UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI";
|
|
43
|
+
import ModelAPI from "../../../UI/Utils/ModelAPI/ModelAPI";
|
|
44
|
+
import Navigation from "../../../UI/Utils/Navigation";
|
|
45
|
+
import {
|
|
46
|
+
CURRENT_PROJECT_ID_STORAGE_KEY,
|
|
47
|
+
LAST_ACCESSED_PROJECT_ID_STORAGE_KEY,
|
|
48
|
+
} from "../../../UI/Utils/Project";
|
|
49
|
+
import User from "../../../UI/Utils/User";
|
|
50
|
+
|
|
51
|
+
jest.mock("axios", () => {
|
|
52
|
+
// Keep the real helpers (axios.isAxiosError, AxiosError) and fake only the call.
|
|
53
|
+
return Object.assign(jest.fn(), jest.requireActual("axios"));
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
/*
|
|
57
|
+
* A PUBLIC DASHBOARD WIDGET'S 401 BELONGS TO THE PUBLIC DASHBOARD.
|
|
58
|
+
*
|
|
59
|
+
* The incident/alert/monitor/host/log/... list widgets are shared with the
|
|
60
|
+
* authenticated dashboard and read through ModelAPI / AnalyticsModelAPI. On a
|
|
61
|
+
* public dashboard they are pointed at /public-dashboard-api/resource-list,
|
|
62
|
+
* which answers 401 when the owner unpublishes the dashboard or the
|
|
63
|
+
* master-password cookie lapses. Sent through the DASHBOARD client, that 401:
|
|
64
|
+
* - POSTed /identity/refresh-token (a failed refresh clears every cookie on
|
|
65
|
+
* the host, the master-password cookie included),
|
|
66
|
+
* - ran the dashboard's User.logout() - which, for a viewer also signed in to
|
|
67
|
+
* the dashboard on the same host, ended their real session once the
|
|
68
|
+
* successful refresh replayed into the same 401 - and
|
|
69
|
+
* - force-navigated to /accounts/login, not a page on a public-dashboard
|
|
70
|
+
* custom domain.
|
|
71
|
+
*
|
|
72
|
+
* These tests register the context the public dashboard page registers
|
|
73
|
+
* (PublicDashboardWidgetContext.build) and run the real widgets, the real
|
|
74
|
+
* ModelAPI / AnalyticsModelAPI and the real BaseAPI / Common API client. A
|
|
75
|
+
* scripted server stands in for axios and answers nothing but the requests
|
|
76
|
+
* each test expects, so a refresh or a replay fails the test. They prove the
|
|
77
|
+
* request goes through the public dashboard's own client: one request, no
|
|
78
|
+
* refresh, no dashboard logout, and the public dashboard's master-password
|
|
79
|
+
* page.
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
const mockedAxios: FakeTransport = axios as unknown as FakeTransport;
|
|
83
|
+
|
|
84
|
+
const DASHBOARD_ID: string = "44444444-4444-4444-8444-444444444444";
|
|
85
|
+
|
|
86
|
+
const COMPONENT_ID: ObjectID = new ObjectID(
|
|
87
|
+
"11111111-1111-4111-8111-111111111111",
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// The viewer's own dashboard project, remembered by this browser.
|
|
91
|
+
const VIEWER_PROJECT_ID: string = "55555555-5555-4555-8555-555555555555";
|
|
92
|
+
|
|
93
|
+
const PUBLIC_API_URL: string = PUBLIC_DASHBOARD_API_URL.toString();
|
|
94
|
+
|
|
95
|
+
const RESOURCE_LIST_URL: string = `${PUBLIC_API_URL}/resource-list/${DASHBOARD_ID}`;
|
|
96
|
+
|
|
97
|
+
const REFRESH_URL: string = URL.fromString(IDENTITY_URL.toString())
|
|
98
|
+
.addRoute("/refresh-token")
|
|
99
|
+
.toString();
|
|
100
|
+
|
|
101
|
+
const MASTER_PASSWORD_ROUTE: Route = new Route("/master-password");
|
|
102
|
+
|
|
103
|
+
const NOT_AUTHENTICATED_BODY: JSONObject = {
|
|
104
|
+
message: "Master password required",
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const EMPTY_LIST_BODY: JSONObject = {
|
|
108
|
+
data: [],
|
|
109
|
+
count: 0,
|
|
110
|
+
skip: 0,
|
|
111
|
+
limit: 10,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
let server: FakeAxiosServer;
|
|
115
|
+
|
|
116
|
+
let navigateSpy: jest.SpiedFunction<typeof Navigation.navigate>;
|
|
117
|
+
|
|
118
|
+
let dashboardLogoutSpy: jest.SpiedFunction<typeof User.logout>;
|
|
119
|
+
|
|
120
|
+
type SentRequestsFunction = () => Array<string>;
|
|
121
|
+
|
|
122
|
+
const sentRequests: SentRequestsFunction = (): Array<string> => {
|
|
123
|
+
return server.sent.map((request: SentRequest): string => {
|
|
124
|
+
return `${request.method.toUpperCase()} ${request.url}`;
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
type ReadFunction = () => Promise<unknown>;
|
|
129
|
+
|
|
130
|
+
const readIncidentList: ReadFunction = async (): Promise<unknown> => {
|
|
131
|
+
return await ModelAPI.getList<Incident>({
|
|
132
|
+
modelType: Incident,
|
|
133
|
+
query: {},
|
|
134
|
+
limit: 10,
|
|
135
|
+
skip: 0,
|
|
136
|
+
select: { title: true },
|
|
137
|
+
sort: {},
|
|
138
|
+
requestOptions: DashboardResourceList.getRequestOptions("incident", {
|
|
139
|
+
componentId: COMPONENT_ID,
|
|
140
|
+
variables: [],
|
|
141
|
+
}),
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const readLogList: ReadFunction = async (): Promise<unknown> => {
|
|
146
|
+
return await AnalyticsModelAPI.getList<Log>({
|
|
147
|
+
modelType: Log,
|
|
148
|
+
query: {},
|
|
149
|
+
limit: 10,
|
|
150
|
+
skip: 0,
|
|
151
|
+
select: { body: true },
|
|
152
|
+
sort: {},
|
|
153
|
+
requestOptions: DashboardResourceList.getRequestOptions("log", {
|
|
154
|
+
componentId: COMPONENT_ID,
|
|
155
|
+
variables: [],
|
|
156
|
+
}),
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
type WidgetPropsFunction = () => DashboardBaseComponentProps;
|
|
161
|
+
|
|
162
|
+
const baseWidgetProps: WidgetPropsFunction =
|
|
163
|
+
(): DashboardBaseComponentProps => {
|
|
164
|
+
return {
|
|
165
|
+
componentId: COMPONENT_ID,
|
|
166
|
+
isEditMode: false,
|
|
167
|
+
isSelected: false,
|
|
168
|
+
key: "public-widget",
|
|
169
|
+
onComponentUpdate: (): void => {},
|
|
170
|
+
totalCurrentDashboardWidthInPx: 1200,
|
|
171
|
+
dashboardCanvasTopInPx: 0,
|
|
172
|
+
dashboardCanvasLeftInPx: 0,
|
|
173
|
+
dashboardCanvasWidthInPx: 1200,
|
|
174
|
+
dashboardCanvasHeightInPx: 800,
|
|
175
|
+
dashboardComponentHeightInPx: 450,
|
|
176
|
+
dashboardComponentWidthInPx: 1200,
|
|
177
|
+
dashboardViewConfig: {
|
|
178
|
+
_type: ObjectType.DashboardViewConfig,
|
|
179
|
+
components: [],
|
|
180
|
+
heightInDashboardUnits: 60,
|
|
181
|
+
},
|
|
182
|
+
dashboardStartAndEndDate: {
|
|
183
|
+
range: TimeRange.CUSTOM,
|
|
184
|
+
startAndEndDate: new InBetween<Date>(
|
|
185
|
+
new Date("2026-08-10T00:00:00.000Z"),
|
|
186
|
+
new Date("2026-08-10T06:00:00.000Z"),
|
|
187
|
+
),
|
|
188
|
+
},
|
|
189
|
+
metricTypes: [],
|
|
190
|
+
refreshTick: 0,
|
|
191
|
+
};
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
type ExpectPublicAuthRedirectFunction = (data: {
|
|
195
|
+
url: string;
|
|
196
|
+
route?: Route | undefined;
|
|
197
|
+
}) => void;
|
|
198
|
+
|
|
199
|
+
/*
|
|
200
|
+
* The whole contract, in one place: the widget's read was the only request
|
|
201
|
+
* (no refresh, no replay), the dashboard session was left alone, the public
|
|
202
|
+
* dashboard's own "logout" ran (it forgets the password was entered), and the
|
|
203
|
+
* viewer is sent to the public dashboard's master-password page - once.
|
|
204
|
+
*/
|
|
205
|
+
const expectPublicAuthRedirect: ExpectPublicAuthRedirectFunction = (data: {
|
|
206
|
+
url: string;
|
|
207
|
+
route?: Route | undefined;
|
|
208
|
+
}): void => {
|
|
209
|
+
expect(sentRequests()).toEqual([`POST ${data.url}`]);
|
|
210
|
+
expect(server.requestsTo(HTTPMethod.POST, REFRESH_URL)).toEqual([]);
|
|
211
|
+
|
|
212
|
+
expect(dashboardLogoutSpy).not.toHaveBeenCalled();
|
|
213
|
+
expect(PublicDashboardUtil.isMasterPasswordValidated()).toBe(false);
|
|
214
|
+
|
|
215
|
+
expect(navigateSpy).toHaveBeenCalledTimes(1);
|
|
216
|
+
expect(navigateSpy).toHaveBeenCalledWith(
|
|
217
|
+
data.route || MASTER_PASSWORD_ROUTE,
|
|
218
|
+
{ forceNavigate: true },
|
|
219
|
+
);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
beforeEach(() => {
|
|
223
|
+
window.localStorage.clear();
|
|
224
|
+
window.sessionStorage.clear();
|
|
225
|
+
window.history.replaceState(null, "", "/");
|
|
226
|
+
|
|
227
|
+
server = new FakeAxiosServer(mockedAxios);
|
|
228
|
+
|
|
229
|
+
PublicDashboardUtil.setDashboardId(new ObjectID(DASHBOARD_ID));
|
|
230
|
+
PublicDashboardUtil.setRequiresMasterPassword(true);
|
|
231
|
+
PublicDashboardUtil.setMasterPasswordValidated(true);
|
|
232
|
+
|
|
233
|
+
navigateSpy = jest
|
|
234
|
+
.spyOn(Navigation, "navigate")
|
|
235
|
+
.mockImplementation((): void => {});
|
|
236
|
+
|
|
237
|
+
// Also keeps the real logout from wiping storage or POSTing /logout.
|
|
238
|
+
dashboardLogoutSpy = jest
|
|
239
|
+
.spyOn(User, "logout")
|
|
240
|
+
.mockImplementation((): void => {});
|
|
241
|
+
|
|
242
|
+
// Navigation.getCurrentRoute needs a router; the viewer is on the dashboard.
|
|
243
|
+
jest.spyOn(Navigation, "getCurrentRoute").mockReturnValue(new Route("/"));
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
afterEach(async () => {
|
|
247
|
+
cleanup();
|
|
248
|
+
await settle();
|
|
249
|
+
|
|
250
|
+
setPublicDashboardContext(null);
|
|
251
|
+
mockedAxios.mockReset();
|
|
252
|
+
jest.restoreAllMocks();
|
|
253
|
+
window.localStorage.clear();
|
|
254
|
+
window.sessionStorage.clear();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
describe("public dashboard widget lists: a 401 goes to the master-password page", () => {
|
|
258
|
+
beforeEach(() => {
|
|
259
|
+
setPublicDashboardContext(
|
|
260
|
+
PublicDashboardWidgetContext.build(new ObjectID(DASHBOARD_ID)),
|
|
261
|
+
);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test("the real incident list widget makes no refresh, keeps the dashboard session and opens the master-password page", async () => {
|
|
265
|
+
server.on(
|
|
266
|
+
HTTPMethod.POST,
|
|
267
|
+
`${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
|
|
268
|
+
[{ status: 401, data: NOT_AUTHENTICATED_BODY }],
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const component: DashboardIncidentListComponent = {
|
|
272
|
+
_type: ObjectType.DashboardComponent,
|
|
273
|
+
componentId: COMPONENT_ID,
|
|
274
|
+
componentType: DashboardComponentType.IncidentList,
|
|
275
|
+
topInDashboardUnits: 0,
|
|
276
|
+
leftInDashboardUnits: 0,
|
|
277
|
+
widthInDashboardUnits: 12,
|
|
278
|
+
heightInDashboardUnits: 5,
|
|
279
|
+
minWidthInDashboardUnits: 6,
|
|
280
|
+
minHeightInDashboardUnits: 3,
|
|
281
|
+
arguments: { title: "Incidents", maxRows: 10 },
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
render(
|
|
285
|
+
<DashboardIncidentListComponentElement
|
|
286
|
+
{...baseWidgetProps()}
|
|
287
|
+
component={component}
|
|
288
|
+
/>,
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
// The widget shows the error in place...
|
|
292
|
+
await screen.findByText(/Master password required/);
|
|
293
|
+
|
|
294
|
+
// ...and the page goes to the public dashboard's password prompt.
|
|
295
|
+
await waitFor(() => {
|
|
296
|
+
expect(navigateSpy).toHaveBeenCalled();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
expectPublicAuthRedirect({
|
|
300
|
+
url: `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test("the real log stream widget (AnalyticsModelAPI) does the same", async () => {
|
|
305
|
+
server.on(HTTPMethod.POST, `${RESOURCE_LIST_URL}/log?limit=10&skip=0`, [
|
|
306
|
+
{ status: 401, data: NOT_AUTHENTICATED_BODY },
|
|
307
|
+
]);
|
|
308
|
+
|
|
309
|
+
const component: DashboardLogStreamComponent = {
|
|
310
|
+
_type: ObjectType.DashboardComponent,
|
|
311
|
+
componentId: COMPONENT_ID,
|
|
312
|
+
componentType: DashboardComponentType.LogStream,
|
|
313
|
+
topInDashboardUnits: 0,
|
|
314
|
+
leftInDashboardUnits: 0,
|
|
315
|
+
widthInDashboardUnits: 12,
|
|
316
|
+
heightInDashboardUnits: 5,
|
|
317
|
+
minWidthInDashboardUnits: 6,
|
|
318
|
+
minHeightInDashboardUnits: 3,
|
|
319
|
+
arguments: { title: "Logs", maxRows: 10 },
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
render(
|
|
323
|
+
<DashboardLogStreamComponentElement
|
|
324
|
+
{...baseWidgetProps()}
|
|
325
|
+
component={component}
|
|
326
|
+
/>,
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
await screen.findByText(/Master password required/);
|
|
330
|
+
|
|
331
|
+
await waitFor(() => {
|
|
332
|
+
expect(navigateSpy).toHaveBeenCalled();
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
expectPublicAuthRedirect({
|
|
336
|
+
url: `${RESOURCE_LIST_URL}/log?limit=10&skip=0`,
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
test("a ModelAPI list read gets its 401 back", async () => {
|
|
341
|
+
server.on(
|
|
342
|
+
HTTPMethod.POST,
|
|
343
|
+
`${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
|
|
344
|
+
[{ status: 401, data: NOT_AUTHENTICATED_BODY }],
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
await expect(readIncidentList()).rejects.toMatchObject({
|
|
348
|
+
statusCode: 401,
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
expectPublicAuthRedirect({
|
|
352
|
+
url: `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test("an AnalyticsModelAPI list read gets its 401 back", async () => {
|
|
357
|
+
server.on(HTTPMethod.POST, `${RESOURCE_LIST_URL}/log?limit=10&skip=0`, [
|
|
358
|
+
{ status: 401, data: NOT_AUTHENTICATED_BODY },
|
|
359
|
+
]);
|
|
360
|
+
|
|
361
|
+
await expect(readLogList()).rejects.toMatchObject({ statusCode: 401 });
|
|
362
|
+
|
|
363
|
+
expectPublicAuthRedirect({
|
|
364
|
+
url: `${RESOURCE_LIST_URL}/log?limit=10&skip=0`,
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
test("the SLO widget's reads (pinned and by name) do the same", async () => {
|
|
369
|
+
server.on(HTTPMethod.POST, `${RESOURCE_LIST_URL}/slo?limit=1&skip=0`, [
|
|
370
|
+
{ status: 401, data: NOT_AUTHENTICATED_BODY },
|
|
371
|
+
]);
|
|
372
|
+
|
|
373
|
+
await expect(
|
|
374
|
+
SloWidgetData.fetchSlo({
|
|
375
|
+
serviceLevelObjectiveId: new ObjectID(
|
|
376
|
+
"22222222-2222-4222-8222-222222222222",
|
|
377
|
+
),
|
|
378
|
+
componentId: COMPONENT_ID,
|
|
379
|
+
}),
|
|
380
|
+
).rejects.toMatchObject({ statusCode: 401 });
|
|
381
|
+
|
|
382
|
+
expectPublicAuthRedirect({
|
|
383
|
+
url: `${RESOURCE_LIST_URL}/slo?limit=1&skip=0`,
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
server.sent.length = 0;
|
|
387
|
+
navigateSpy.mockClear();
|
|
388
|
+
|
|
389
|
+
const byNameUrl: string = `${RESOURCE_LIST_URL}/slo?limit=${SLO_WIDGET_NAME_MATCH_LIMIT}&skip=0`;
|
|
390
|
+
|
|
391
|
+
server.on(HTTPMethod.POST, byNameUrl, [
|
|
392
|
+
{ status: 401, data: NOT_AUTHENTICATED_BODY },
|
|
393
|
+
]);
|
|
394
|
+
|
|
395
|
+
await expect(
|
|
396
|
+
SloWidgetData.fetchSlosByName({
|
|
397
|
+
sloName: "Checkout availability",
|
|
398
|
+
componentId: COMPONENT_ID,
|
|
399
|
+
variables: [],
|
|
400
|
+
}),
|
|
401
|
+
).rejects.toMatchObject({ statusCode: 401 });
|
|
402
|
+
|
|
403
|
+
expectPublicAuthRedirect({ url: byNameUrl });
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
/*
|
|
407
|
+
* Before the fix, a viewer who was ALSO signed in to the dashboard on the
|
|
408
|
+
* same host had the refresh succeed, the replay 401 again, and
|
|
409
|
+
* User.logout() end their real dashboard session.
|
|
410
|
+
*/
|
|
411
|
+
test("a viewer also signed in to the dashboard keeps their dashboard session", async () => {
|
|
412
|
+
server
|
|
413
|
+
.on(HTTPMethod.POST, `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`, [
|
|
414
|
+
{ status: 401, data: NOT_AUTHENTICATED_BODY },
|
|
415
|
+
])
|
|
416
|
+
.on(HTTPMethod.POST, REFRESH_URL, [{ status: 200 }]);
|
|
417
|
+
|
|
418
|
+
await expect(readIncidentList()).rejects.toMatchObject({
|
|
419
|
+
statusCode: 401,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
expectPublicAuthRedirect({
|
|
423
|
+
url: `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
test("the preview of a protected dashboard goes to the preview's master-password page", async () => {
|
|
428
|
+
window.history.replaceState(
|
|
429
|
+
null,
|
|
430
|
+
"",
|
|
431
|
+
`/public-dashboard/${DASHBOARD_ID}/view`,
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
server.on(
|
|
435
|
+
HTTPMethod.POST,
|
|
436
|
+
`${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
|
|
437
|
+
[{ status: 401, data: NOT_AUTHENTICATED_BODY }],
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
await expect(readIncidentList()).rejects.toMatchObject({
|
|
441
|
+
statusCode: 401,
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
expectPublicAuthRedirect({
|
|
445
|
+
url: `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`,
|
|
446
|
+
route: new Route(`/public-dashboard/${DASHBOARD_ID}/master-password`),
|
|
447
|
+
});
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
// The metric and SLO-history reads were already on the public client.
|
|
451
|
+
test("the page's postJSON reads never refresh either", async () => {
|
|
452
|
+
const url: string = `${PUBLIC_API_URL}/metrics-aggregate/${DASHBOARD_ID}`;
|
|
453
|
+
|
|
454
|
+
server.on(HTTPMethod.POST, url, [
|
|
455
|
+
{ status: 401, data: NOT_AUTHENTICATED_BODY },
|
|
456
|
+
]);
|
|
457
|
+
|
|
458
|
+
const context: PublicDashboardContext | null = getPublicDashboardContext();
|
|
459
|
+
|
|
460
|
+
if (!context) {
|
|
461
|
+
throw new Error("The public dashboard context should be set.");
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const result: HTTPResponse<JSONObject> | HTTPErrorResponse =
|
|
465
|
+
await context.postJSON(`/metrics-aggregate/${DASHBOARD_ID}`, {});
|
|
466
|
+
|
|
467
|
+
expect(result).toBeInstanceOf(HTTPErrorResponse);
|
|
468
|
+
expect(result.statusCode).toBe(401);
|
|
469
|
+
|
|
470
|
+
expectPublicAuthRedirect({ url });
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
/*
|
|
474
|
+
* The public client sends its own, empty, tenant. The viewer's remembered
|
|
475
|
+
* dashboard project must not override it: a stale or foreign one turned a
|
|
476
|
+
* public widget read into a 405 (tenant not found) that the page treats as
|
|
477
|
+
* a login event, while the dashboard's own reads - sent without it - kept
|
|
478
|
+
* succeeding.
|
|
479
|
+
*/
|
|
480
|
+
test("list reads carry the public dashboard's headers, not the viewer's dashboard project", async () => {
|
|
481
|
+
window.localStorage.setItem(
|
|
482
|
+
LAST_ACCESSED_PROJECT_ID_STORAGE_KEY,
|
|
483
|
+
JSON.stringify(VIEWER_PROJECT_ID),
|
|
484
|
+
);
|
|
485
|
+
window.sessionStorage.setItem(
|
|
486
|
+
CURRENT_PROJECT_ID_STORAGE_KEY,
|
|
487
|
+
JSON.stringify(VIEWER_PROJECT_ID),
|
|
488
|
+
);
|
|
489
|
+
|
|
490
|
+
server
|
|
491
|
+
.on(HTTPMethod.POST, `${RESOURCE_LIST_URL}/incident?limit=10&skip=0`, [
|
|
492
|
+
{ status: 200, data: EMPTY_LIST_BODY },
|
|
493
|
+
])
|
|
494
|
+
.on(HTTPMethod.POST, `${RESOURCE_LIST_URL}/log?limit=10&skip=0`, [
|
|
495
|
+
{ status: 200, data: EMPTY_LIST_BODY },
|
|
496
|
+
]);
|
|
497
|
+
|
|
498
|
+
await readIncidentList();
|
|
499
|
+
await readLogList();
|
|
500
|
+
|
|
501
|
+
expect(server.sent).toHaveLength(2);
|
|
502
|
+
|
|
503
|
+
for (const request of server.sent) {
|
|
504
|
+
expect(request.headers["dashboard-id"]).toBe(DASHBOARD_ID);
|
|
505
|
+
expect(request.headers["tenantid"]).toBe("");
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
expect(navigateSpy).not.toHaveBeenCalled();
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
test("the page's context routes list reads through the public dashboard's client", () => {
|
|
512
|
+
const context: PublicDashboardContext = PublicDashboardWidgetContext.build(
|
|
513
|
+
new ObjectID(DASHBOARD_ID),
|
|
514
|
+
);
|
|
515
|
+
|
|
516
|
+
expect(context.apiClient).toBe(PublicDashboardAPI);
|
|
517
|
+
expect(context.apiUrl.toString()).toBe(PUBLIC_API_URL);
|
|
518
|
+
|
|
519
|
+
expect(DashboardResourceList.getRequestOptions("incident")?.apiClient).toBe(
|
|
520
|
+
PublicDashboardAPI,
|
|
521
|
+
);
|
|
522
|
+
expect(
|
|
523
|
+
DashboardResourceList.getRequestOptions("log", {
|
|
524
|
+
componentId: COMPONENT_ID,
|
|
525
|
+
variables: [],
|
|
526
|
+
})?.apiClient,
|
|
527
|
+
).toBe(PublicDashboardAPI);
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
/*
|
|
532
|
+
* The fix must not reach the authenticated dashboard: without a public
|
|
533
|
+
* context its reads still go through the dashboard client, which still
|
|
534
|
+
* refreshes an expired session, still logs out when that fails, and still
|
|
535
|
+
* scopes the read to the viewer's project.
|
|
536
|
+
*/
|
|
537
|
+
describe("authenticated dashboard widget lists keep the dashboard client", () => {
|
|
538
|
+
const DASHBOARD_API_URL: string = `${DASHBOARD_ORIGIN}/api`;
|
|
539
|
+
|
|
540
|
+
const INCIDENT_LIST_URL: string = `${DASHBOARD_API_URL}/incident/get-list?limit=10&skip=0`;
|
|
541
|
+
|
|
542
|
+
const LOG_LIST_URL: string = `${DASHBOARD_API_URL}/logs/get-list?limit=10&skip=0`;
|
|
543
|
+
|
|
544
|
+
const readDashboardIncidentList: ReadFunction =
|
|
545
|
+
async (): Promise<unknown> => {
|
|
546
|
+
return await ModelAPI.getList<Incident>({
|
|
547
|
+
modelType: Incident,
|
|
548
|
+
query: {},
|
|
549
|
+
limit: 10,
|
|
550
|
+
skip: 0,
|
|
551
|
+
select: { title: true },
|
|
552
|
+
sort: {},
|
|
553
|
+
requestOptions: DashboardResourceList.getRequestOptions("incident"),
|
|
554
|
+
});
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
beforeEach(() => {
|
|
558
|
+
window.sessionStorage.setItem(
|
|
559
|
+
CURRENT_PROJECT_ID_STORAGE_KEY,
|
|
560
|
+
JSON.stringify(VIEWER_PROJECT_ID),
|
|
561
|
+
);
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
test("a 401 refreshes the session and replays the read, scoped to the viewer's project", async () => {
|
|
565
|
+
server
|
|
566
|
+
.on(HTTPMethod.POST, INCIDENT_LIST_URL, [
|
|
567
|
+
{ status: 401, data: { message: "Session expired" } },
|
|
568
|
+
{ status: 200, data: EMPTY_LIST_BODY },
|
|
569
|
+
])
|
|
570
|
+
.on(HTTPMethod.POST, REFRESH_URL, [{ status: 200 }]);
|
|
571
|
+
|
|
572
|
+
await expect(readDashboardIncidentList()).resolves.toMatchObject({
|
|
573
|
+
data: [],
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
expect(sentRequests()).toEqual([
|
|
577
|
+
`POST ${INCIDENT_LIST_URL}`,
|
|
578
|
+
`POST ${REFRESH_URL}`,
|
|
579
|
+
`POST ${INCIDENT_LIST_URL}`,
|
|
580
|
+
]);
|
|
581
|
+
expect(server.sent[0]!.headers["tenantid"]).toBe(VIEWER_PROJECT_ID);
|
|
582
|
+
expect(dashboardLogoutSpy).not.toHaveBeenCalled();
|
|
583
|
+
expect(navigateSpy).not.toHaveBeenCalled();
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
test("a refused refresh still logs the dashboard user out, for model and analytics reads", async () => {
|
|
587
|
+
server
|
|
588
|
+
.on(HTTPMethod.POST, INCIDENT_LIST_URL, [
|
|
589
|
+
{ status: 401, data: { message: "Session expired" } },
|
|
590
|
+
])
|
|
591
|
+
.on(HTTPMethod.POST, LOG_LIST_URL, [
|
|
592
|
+
{ status: 401, data: { message: "Session expired" } },
|
|
593
|
+
])
|
|
594
|
+
.on(HTTPMethod.POST, REFRESH_URL, [{ status: 401 }, { status: 401 }]);
|
|
595
|
+
|
|
596
|
+
await expect(readDashboardIncidentList()).rejects.toMatchObject({
|
|
597
|
+
statusCode: 401,
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
expect(server.requestsTo(HTTPMethod.POST, REFRESH_URL)).toHaveLength(1);
|
|
601
|
+
expect(dashboardLogoutSpy).toHaveBeenCalled();
|
|
602
|
+
expect(navigateSpy).toHaveBeenCalledWith(new Route("/accounts/login"), {
|
|
603
|
+
forceNavigate: true,
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
dashboardLogoutSpy.mockClear();
|
|
607
|
+
|
|
608
|
+
await expect(
|
|
609
|
+
AnalyticsModelAPI.getList<Log>({
|
|
610
|
+
modelType: Log,
|
|
611
|
+
query: {},
|
|
612
|
+
limit: 10,
|
|
613
|
+
skip: 0,
|
|
614
|
+
select: { body: true },
|
|
615
|
+
sort: {},
|
|
616
|
+
requestOptions: DashboardResourceList.getRequestOptions("log"),
|
|
617
|
+
}),
|
|
618
|
+
).rejects.toMatchObject({ statusCode: 401 });
|
|
619
|
+
|
|
620
|
+
expect(server.requestsTo(HTTPMethod.POST, REFRESH_URL)).toHaveLength(2);
|
|
621
|
+
expect(dashboardLogoutSpy).toHaveBeenCalled();
|
|
622
|
+
});
|
|
623
|
+
});
|
|
@@ -142,10 +142,10 @@ const SECRET_COLUMNS: Array<string> = [
|
|
|
142
142
|
"tokenHash",
|
|
143
143
|
"token",
|
|
144
144
|
"previousTokenHash",
|
|
145
|
-
"previousTokenExpiresAt",
|
|
146
145
|
];
|
|
147
146
|
|
|
148
147
|
const BOOKKEEPING_COLUMNS: Array<string> = [
|
|
148
|
+
"previousTokenExpiresAt",
|
|
149
149
|
"tokenHint",
|
|
150
150
|
"rotatedAt",
|
|
151
151
|
"lastFetchedAt",
|
|
@@ -443,6 +443,28 @@ describe("On-call calendar feed token columns", () => {
|
|
|
443
443
|
});
|
|
444
444
|
|
|
445
445
|
describe("On-call calendar feed settings and bookkeeping", () => {
|
|
446
|
+
test.each(feedSpecs())(
|
|
447
|
+
"%s exposes the old link expiry as read-only status metadata",
|
|
448
|
+
(_name: string, spec: FeedSpec) => {
|
|
449
|
+
const model: BaseModel = new spec.modelType();
|
|
450
|
+
const metadata: TableColumnMetadata = model.getTableColumnMetadata(
|
|
451
|
+
"previousTokenExpiresAt",
|
|
452
|
+
);
|
|
453
|
+
|
|
454
|
+
expect(model.getColumnAccessControlFor("previousTokenExpiresAt")).toEqual(
|
|
455
|
+
{
|
|
456
|
+
create: [],
|
|
457
|
+
read: model.readRecordPermissions,
|
|
458
|
+
update: [],
|
|
459
|
+
},
|
|
460
|
+
);
|
|
461
|
+
expect(model.readRecordPermissions.length).toBeGreaterThan(0);
|
|
462
|
+
expect(metadata.computed).toBe(true);
|
|
463
|
+
expect(metadata.canReadOnRelationQuery).toBe(false);
|
|
464
|
+
expect(metadata.hideColumnInDocumentation).toBe(true);
|
|
465
|
+
},
|
|
466
|
+
);
|
|
467
|
+
|
|
446
468
|
test.each(feedSpecs())(
|
|
447
469
|
"%s lets its readers read and its editors update exactly the settings columns",
|
|
448
470
|
(_name: string, spec: FeedSpec) => {
|