@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,394 @@
|
|
|
1
|
+
import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
2
|
+
import Entities from "../../../Models/DatabaseModels/Index";
|
|
3
|
+
import TeamMember from "../../../Models/DatabaseModels/TeamMember";
|
|
4
|
+
import BaseAPI from "../../../Server/API/BaseAPI";
|
|
5
|
+
import PostgresAppInstance from "../../../Server/Infrastructure/PostgresDatabase";
|
|
6
|
+
import DatabaseService from "../../../Server/Services/DatabaseService";
|
|
7
|
+
import Select from "../../../Server/Types/Database/Select";
|
|
8
|
+
import {
|
|
9
|
+
ExpressResponse,
|
|
10
|
+
OneUptimeRequest,
|
|
11
|
+
} from "../../../Server/Utils/Express";
|
|
12
|
+
import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
13
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
14
|
+
import JSONFunctions from "../../../Types/JSONFunctions";
|
|
15
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
16
|
+
import Permission from "../../../Types/Permission";
|
|
17
|
+
import UserType from "../../../Types/UserType";
|
|
18
|
+
import { DataSource } from "typeorm";
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* The handler receives an already-authenticated request and uses a dedicated
|
|
22
|
+
* DataSource below. Avoid loading unrelated login, billing, and boot-migration
|
|
23
|
+
* services; no permission check, repository operation, or serializer is mocked.
|
|
24
|
+
*/
|
|
25
|
+
jest.mock("../../../Server/Middleware/UserAuthorization", () => {
|
|
26
|
+
return { getUserMiddleware: jest.fn() };
|
|
27
|
+
});
|
|
28
|
+
jest.mock("../../../Server/Services/ProjectService", () => {
|
|
29
|
+
return { getCurrentPlan: jest.fn() };
|
|
30
|
+
});
|
|
31
|
+
jest.mock("../../../Server/Infrastructure/Postgres/DataSourceOptions", () => {
|
|
32
|
+
return {};
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
* Opt in with RUN_POSTGRES_TEAM_MEMBER_PERMISSION_TESTS=true and config.env.
|
|
37
|
+
* Only table definitions are copied from public. Every row is synthetic and
|
|
38
|
+
* every read/write is directed to an isolated schema that is removed below.
|
|
39
|
+
* The permission pipeline, request-header translation, TypeORM joins, and
|
|
40
|
+
* response serialization run unchanged.
|
|
41
|
+
*/
|
|
42
|
+
const describePostgres: typeof describe =
|
|
43
|
+
process.env["RUN_POSTGRES_TEAM_MEMBER_PERMISSION_TESTS"] === "true"
|
|
44
|
+
? describe
|
|
45
|
+
: describe.skip;
|
|
46
|
+
|
|
47
|
+
describePostgres(
|
|
48
|
+
"multi-tenant team-member read authorization against Postgres",
|
|
49
|
+
() => {
|
|
50
|
+
const schema: string = `team_member_permission_test_${ObjectID.generate().toString().replace(/-/g, "")}`;
|
|
51
|
+
const userId: ObjectID = ObjectID.generate();
|
|
52
|
+
const otherUserId: ObjectID = ObjectID.generate();
|
|
53
|
+
const inviterId: ObjectID = ObjectID.generate();
|
|
54
|
+
const firstProjectId: ObjectID = ObjectID.generate();
|
|
55
|
+
const secondProjectId: ObjectID = ObjectID.generate();
|
|
56
|
+
const firstTeamId: ObjectID = ObjectID.generate();
|
|
57
|
+
const secondTeamId: ObjectID = ObjectID.generate();
|
|
58
|
+
const firstInvitationId: ObjectID = ObjectID.generate();
|
|
59
|
+
const secondInvitationId: ObjectID = ObjectID.generate();
|
|
60
|
+
const otherInvitationId: ObjectID = ObjectID.generate();
|
|
61
|
+
const acceptedMembershipId: ObjectID = ObjectID.generate();
|
|
62
|
+
const passwordHash: string = "synthetic-inviter-password-hash";
|
|
63
|
+
const resetToken: string = "synthetic-inviter-reset-token";
|
|
64
|
+
const privateTeamDescription: string = "Synthetic private team description";
|
|
65
|
+
const service: DatabaseService<TeamMember> = new DatabaseService(
|
|
66
|
+
TeamMember,
|
|
67
|
+
);
|
|
68
|
+
const api: BaseAPI<TeamMember, DatabaseService<TeamMember>> = new BaseAPI(
|
|
69
|
+
TeamMember,
|
|
70
|
+
service,
|
|
71
|
+
);
|
|
72
|
+
let database: DataSource;
|
|
73
|
+
|
|
74
|
+
beforeAll(async () => {
|
|
75
|
+
database = new DataSource({
|
|
76
|
+
type: "postgres",
|
|
77
|
+
host:
|
|
78
|
+
process.env["TEAM_MEMBER_PERMISSION_TEST_DATABASE_HOST"] ||
|
|
79
|
+
"localhost",
|
|
80
|
+
port: Number(
|
|
81
|
+
process.env["TEAM_MEMBER_PERMISSION_TEST_DATABASE_PORT"] || "5400",
|
|
82
|
+
),
|
|
83
|
+
username: process.env["DATABASE_USERNAME"] || "postgres",
|
|
84
|
+
password: process.env["DATABASE_PASSWORD"] || "password",
|
|
85
|
+
database: process.env["DATABASE_NAME"] || "oneuptimedb",
|
|
86
|
+
entities: Entities,
|
|
87
|
+
schema,
|
|
88
|
+
synchronize: false,
|
|
89
|
+
extra: { options: `-c search_path=${schema},public` },
|
|
90
|
+
});
|
|
91
|
+
await database.initialize();
|
|
92
|
+
await database.query(`CREATE SCHEMA "${schema}"`);
|
|
93
|
+
for (const table of ["User", "Project", "Team", "TeamMember"]) {
|
|
94
|
+
await database.query(
|
|
95
|
+
`CREATE TABLE "${schema}"."${table}" (LIKE public."${table}" INCLUDING ALL)`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
jest.spyOn(PostgresAppInstance, "isConnected").mockReturnValue(true);
|
|
99
|
+
jest
|
|
100
|
+
.spyOn(PostgresAppInstance, "getDataSource")
|
|
101
|
+
.mockReturnValue(database);
|
|
102
|
+
|
|
103
|
+
for (const id of [userId, otherUserId, inviterId]) {
|
|
104
|
+
await database.query(
|
|
105
|
+
`INSERT INTO "${schema}"."User"
|
|
106
|
+
("_id", "name", "email", "slug", "password", "resetPasswordToken", "version")
|
|
107
|
+
VALUES ($1, 'Synthetic User', $2, $3, $4, $5, 1)`,
|
|
108
|
+
[
|
|
109
|
+
id.toString(),
|
|
110
|
+
`${id.toString()}@example.com`,
|
|
111
|
+
id.toString(),
|
|
112
|
+
passwordHash,
|
|
113
|
+
resetToken,
|
|
114
|
+
],
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
for (const [projectId, teamId, projectName, teamName] of [
|
|
118
|
+
[
|
|
119
|
+
firstProjectId,
|
|
120
|
+
firstTeamId,
|
|
121
|
+
"First invitation project",
|
|
122
|
+
"First invitation team",
|
|
123
|
+
],
|
|
124
|
+
[
|
|
125
|
+
secondProjectId,
|
|
126
|
+
secondTeamId,
|
|
127
|
+
"Second invitation project",
|
|
128
|
+
"Second invitation team",
|
|
129
|
+
],
|
|
130
|
+
] as Array<[ObjectID, ObjectID, string, string]>) {
|
|
131
|
+
await database.query(
|
|
132
|
+
`INSERT INTO "${schema}"."Project" ("_id", "name", "slug", "version") VALUES ($1, $2, $3, 1)`,
|
|
133
|
+
[projectId.toString(), projectName, projectId.toString()],
|
|
134
|
+
);
|
|
135
|
+
await database.query(
|
|
136
|
+
`INSERT INTO "${schema}"."Team" ("_id", "projectId", "name", "slug", "description", "version")
|
|
137
|
+
VALUES ($1, $2, $3, $4, $5, 1)`,
|
|
138
|
+
[
|
|
139
|
+
teamId.toString(),
|
|
140
|
+
projectId.toString(),
|
|
141
|
+
teamName,
|
|
142
|
+
teamId.toString(),
|
|
143
|
+
privateTeamDescription,
|
|
144
|
+
],
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
for (const [id, memberId, projectId, teamId, accepted] of [
|
|
148
|
+
[firstInvitationId, userId, firstProjectId, firstTeamId, false],
|
|
149
|
+
[secondInvitationId, userId, secondProjectId, secondTeamId, false],
|
|
150
|
+
[otherInvitationId, otherUserId, firstProjectId, firstTeamId, false],
|
|
151
|
+
[acceptedMembershipId, userId, firstProjectId, firstTeamId, true],
|
|
152
|
+
] as Array<[ObjectID, ObjectID, ObjectID, ObjectID, boolean]>) {
|
|
153
|
+
await database.query(
|
|
154
|
+
`INSERT INTO "${schema}"."TeamMember"
|
|
155
|
+
("_id", "userId", "projectId", "teamId", "createdByUserId", "hasAcceptedInvitation", "version")
|
|
156
|
+
VALUES ($1, $2, $3, $4, $5, $6, 1)`,
|
|
157
|
+
[
|
|
158
|
+
id.toString(),
|
|
159
|
+
memberId.toString(),
|
|
160
|
+
projectId.toString(),
|
|
161
|
+
teamId.toString(),
|
|
162
|
+
inviterId.toString(),
|
|
163
|
+
accepted,
|
|
164
|
+
],
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
afterAll(async () => {
|
|
170
|
+
jest.restoreAllMocks();
|
|
171
|
+
if (database?.isInitialized) {
|
|
172
|
+
await database.query(`DROP SCHEMA IF EXISTS "${schema}" CASCADE`);
|
|
173
|
+
await database.destroy();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
function props(
|
|
178
|
+
isMultiTenantRequest: boolean = true,
|
|
179
|
+
): DatabaseCommonInteractionProps {
|
|
180
|
+
return {
|
|
181
|
+
userId,
|
|
182
|
+
userType: UserType.User,
|
|
183
|
+
isMultiTenantRequest,
|
|
184
|
+
userGlobalAccessPermission: {
|
|
185
|
+
_type: "UserGlobalAccessPermission",
|
|
186
|
+
globalPermissions: [Permission.User, Permission.CurrentUser],
|
|
187
|
+
// An invited user may not belong to any project yet.
|
|
188
|
+
projectIds: [],
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function safeSelect(): Select<TeamMember> {
|
|
194
|
+
return {
|
|
195
|
+
_id: true,
|
|
196
|
+
userId: true,
|
|
197
|
+
hasAcceptedInvitation: true,
|
|
198
|
+
team: { name: true },
|
|
199
|
+
project: { name: true },
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async function getList(data: {
|
|
204
|
+
select: Select<TeamMember>;
|
|
205
|
+
query?: JSONObject;
|
|
206
|
+
isMultiTenantRequest?: boolean;
|
|
207
|
+
}): Promise<JSONObject> {
|
|
208
|
+
const requestProps: DatabaseCommonInteractionProps = props();
|
|
209
|
+
const req: OneUptimeRequest = {
|
|
210
|
+
headers:
|
|
211
|
+
data.isMultiTenantRequest === false
|
|
212
|
+
? {}
|
|
213
|
+
: { "is-multi-tenant-query": "true" },
|
|
214
|
+
query: {},
|
|
215
|
+
body: JSONFunctions.serialize({
|
|
216
|
+
query: data.query || {},
|
|
217
|
+
select: data.select,
|
|
218
|
+
limit: 20,
|
|
219
|
+
}),
|
|
220
|
+
userAuthorization: { userId },
|
|
221
|
+
userGlobalAccessPermission: requestProps.userGlobalAccessPermission,
|
|
222
|
+
userType: UserType.User,
|
|
223
|
+
} as unknown as OneUptimeRequest;
|
|
224
|
+
let body: JSONObject | undefined;
|
|
225
|
+
const res: ExpressResponse = {
|
|
226
|
+
status: jest.fn().mockReturnThis(),
|
|
227
|
+
set: jest.fn().mockReturnThis(),
|
|
228
|
+
send: jest.fn((responseBody: JSONObject) => {
|
|
229
|
+
// Express serializes ListData and its database property wrappers.
|
|
230
|
+
body = JSON.parse(JSON.stringify(responseBody)) as JSONObject;
|
|
231
|
+
}),
|
|
232
|
+
} as unknown as ExpressResponse;
|
|
233
|
+
await api.getList(req, res);
|
|
234
|
+
expect(res.status).toHaveBeenCalledWith(200);
|
|
235
|
+
expect(body).toBeDefined();
|
|
236
|
+
return body as JSONObject;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
test("the privileged control reaches synthetic inviter secrets through the real join and serializer", async () => {
|
|
240
|
+
const records: Array<TeamMember> = await service.findBy({
|
|
241
|
+
query: { _id: firstInvitationId.toString() },
|
|
242
|
+
select: { createdByUser: { password: true, resetPasswordToken: true } },
|
|
243
|
+
skip: 0,
|
|
244
|
+
limit: 1,
|
|
245
|
+
props: { isRoot: true },
|
|
246
|
+
});
|
|
247
|
+
expect(records).toHaveLength(1);
|
|
248
|
+
const serialized: string = JSON.stringify(
|
|
249
|
+
BaseModel.toJSONArray(records, TeamMember),
|
|
250
|
+
);
|
|
251
|
+
expect(serialized).toContain(passwordHash);
|
|
252
|
+
expect(serialized).toContain(resetToken);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test.each([
|
|
256
|
+
[
|
|
257
|
+
"inviter password hash",
|
|
258
|
+
{ createdByUser: { password: true } },
|
|
259
|
+
"permissions to select on - createdByUser",
|
|
260
|
+
],
|
|
261
|
+
[
|
|
262
|
+
"inviter password reset token",
|
|
263
|
+
{ createdByUser: { resetPasswordToken: true } },
|
|
264
|
+
"permissions to select on - createdByUser",
|
|
265
|
+
],
|
|
266
|
+
[
|
|
267
|
+
"restricted team field",
|
|
268
|
+
{ team: { description: true } },
|
|
269
|
+
"Column description on Team does not support read on relation query",
|
|
270
|
+
],
|
|
271
|
+
[
|
|
272
|
+
"restricted user relation",
|
|
273
|
+
{ user: { password: true } },
|
|
274
|
+
"permissions to select on - user",
|
|
275
|
+
],
|
|
276
|
+
[
|
|
277
|
+
"deep relation",
|
|
278
|
+
{ team: { createdByUser: { password: true } } },
|
|
279
|
+
"You cannot query deep relations",
|
|
280
|
+
],
|
|
281
|
+
] as Array<[string, Select<TeamMember>, string]>)(
|
|
282
|
+
"rejects a multi-tenant API selection of %s",
|
|
283
|
+
async (
|
|
284
|
+
_label: string,
|
|
285
|
+
select: Select<TeamMember>,
|
|
286
|
+
expectedError: string,
|
|
287
|
+
) => {
|
|
288
|
+
await expect(getList({ select })).rejects.toThrow(expectedError);
|
|
289
|
+
},
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
test("the same nested credential projection is already denied without the multi-tenant header", async () => {
|
|
293
|
+
await expect(
|
|
294
|
+
getList({
|
|
295
|
+
select: {
|
|
296
|
+
createdByUser: { password: true, resetPasswordToken: true },
|
|
297
|
+
},
|
|
298
|
+
isMultiTenantRequest: false,
|
|
299
|
+
}),
|
|
300
|
+
).rejects.toThrow("permissions to select on - createdByUser");
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test.each([true, false])(
|
|
304
|
+
"lists pending invitations and their safe labels with no project memberships (multi-tenant=%s)",
|
|
305
|
+
async (isMultiTenantRequest: boolean) => {
|
|
306
|
+
const response: JSONObject = await getList({
|
|
307
|
+
select: safeSelect(),
|
|
308
|
+
query: { hasAcceptedInvitation: false },
|
|
309
|
+
isMultiTenantRequest,
|
|
310
|
+
});
|
|
311
|
+
expect(response["count"]).toBe(2);
|
|
312
|
+
const rows: Array<JSONObject> = response["data"] as Array<JSONObject>;
|
|
313
|
+
expect(rows).toHaveLength(2);
|
|
314
|
+
expect(
|
|
315
|
+
rows
|
|
316
|
+
.map((row: JSONObject) => {
|
|
317
|
+
return row["_id"];
|
|
318
|
+
})
|
|
319
|
+
.sort(),
|
|
320
|
+
).toEqual(
|
|
321
|
+
[firstInvitationId.toString(), secondInvitationId.toString()].sort(),
|
|
322
|
+
);
|
|
323
|
+
const serialized: string = JSON.stringify(response);
|
|
324
|
+
expect(serialized).toContain("First invitation project");
|
|
325
|
+
expect(serialized).toContain("Second invitation project");
|
|
326
|
+
expect(serialized).toContain("First invitation team");
|
|
327
|
+
expect(serialized).toContain("Second invitation team");
|
|
328
|
+
expect(serialized).not.toContain(otherInvitationId.toString());
|
|
329
|
+
expect(serialized).not.toContain(passwordHash);
|
|
330
|
+
expect(serialized).not.toContain(resetToken);
|
|
331
|
+
expect(serialized).not.toContain(privateTeamDescription);
|
|
332
|
+
},
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
test("caller filters remain effective for both list and count", async () => {
|
|
336
|
+
const response: JSONObject = await getList({
|
|
337
|
+
select: safeSelect(),
|
|
338
|
+
query: { projectId: secondProjectId, hasAcceptedInvitation: false },
|
|
339
|
+
});
|
|
340
|
+
expect(response["count"]).toBe(1);
|
|
341
|
+
expect(response["data"]).toHaveLength(1);
|
|
342
|
+
expect(JSON.stringify(response)).toContain(secondInvitationId.toString());
|
|
343
|
+
expect(JSON.stringify(response)).not.toContain(
|
|
344
|
+
firstInvitationId.toString(),
|
|
345
|
+
);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test("count authorization rejects predicates on forbidden columns", async () => {
|
|
349
|
+
await expect(
|
|
350
|
+
service.countBy({
|
|
351
|
+
query: { createdByUserId: inviterId },
|
|
352
|
+
props: props(),
|
|
353
|
+
}),
|
|
354
|
+
).rejects.toThrow("permissions to query on - createdByUserId");
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test("safe counts are restricted to the current user's rows", async () => {
|
|
358
|
+
expect(
|
|
359
|
+
(await service.countBy({ query: {}, props: props() })).toNumber(),
|
|
360
|
+
).toBe(3);
|
|
361
|
+
expect(
|
|
362
|
+
(
|
|
363
|
+
await service.countBy({
|
|
364
|
+
query: { hasAcceptedInvitation: false },
|
|
365
|
+
props: props(),
|
|
366
|
+
})
|
|
367
|
+
).toNumber(),
|
|
368
|
+
).toBe(2);
|
|
369
|
+
expect(
|
|
370
|
+
(
|
|
371
|
+
await service.countBy({ query: {}, props: { isRoot: true } })
|
|
372
|
+
).toNumber(),
|
|
373
|
+
).toBe(4);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
test("a caller cannot redirect the current-user scope to another member", async () => {
|
|
377
|
+
await expect(
|
|
378
|
+
getList({ select: safeSelect(), query: { userId: otherUserId } }),
|
|
379
|
+
).rejects.toThrow("permission to access another user's Team Member");
|
|
380
|
+
await expect(
|
|
381
|
+
service.countBy({ query: { userId: otherUserId }, props: props() }),
|
|
382
|
+
).rejects.toThrow("permission to access another user's Team Member");
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
test("an explicit foreign membership ID returns no row and a zero count", async () => {
|
|
386
|
+
const response: JSONObject = await getList({
|
|
387
|
+
select: safeSelect(),
|
|
388
|
+
query: { _id: otherInvitationId.toString() },
|
|
389
|
+
});
|
|
390
|
+
expect(response["data"]).toEqual([]);
|
|
391
|
+
expect(response["count"]).toBe(0);
|
|
392
|
+
});
|
|
393
|
+
},
|
|
394
|
+
);
|
|
@@ -103,6 +103,11 @@ function propsWith(
|
|
|
103
103
|
return {
|
|
104
104
|
userId: USER_ID,
|
|
105
105
|
tenantId: tenantId,
|
|
106
|
+
userGlobalAccessPermission: {
|
|
107
|
+
_type: "UserGlobalAccessPermission",
|
|
108
|
+
projectIds: [tenantId],
|
|
109
|
+
globalPermissions: [Permission.Public, Permission.User],
|
|
110
|
+
},
|
|
106
111
|
userTenantAccessPermission: {
|
|
107
112
|
[tenantId.toString()]: tenantPermission,
|
|
108
113
|
},
|
|
@@ -117,6 +122,7 @@ function makePermission(data?: {
|
|
|
117
122
|
scope?: PermissionScope | undefined;
|
|
118
123
|
}): TeamPermission {
|
|
119
124
|
const permission: TeamPermission = new TeamPermission();
|
|
125
|
+
permission.id = ObjectID.generate();
|
|
120
126
|
permission.projectId = data?.projectId || PROJECT_ID;
|
|
121
127
|
permission.teamId = data?.teamId || TEAM_ID;
|
|
122
128
|
permission.permission = data?.permission || Permission.ProjectMember;
|
|
@@ -2,10 +2,13 @@ import TelemetryIngestionKeyService, {
|
|
|
2
2
|
Service,
|
|
3
3
|
} from "../../../Server/Services/TelemetryIngestionKeyService";
|
|
4
4
|
import PayAsYouGoBillingService from "../../../Server/Services/PayAsYouGoBillingService";
|
|
5
|
+
import BillingService from "../../../Server/Services/BillingService";
|
|
6
|
+
import ProjectService from "../../../Server/Services/ProjectService";
|
|
5
7
|
import TelemetryIngest, {
|
|
6
8
|
TelemetryRequest,
|
|
7
9
|
} from "../../../Server/Middleware/TelemetryIngest";
|
|
8
10
|
import TelemetryIngestionKey from "../../../Models/DatabaseModels/TelemetryIngestionKey";
|
|
11
|
+
import Project from "../../../Models/DatabaseModels/Project";
|
|
9
12
|
import CreateBy from "../../../Server/Types/Database/CreateBy";
|
|
10
13
|
import UpdateBy from "../../../Server/Types/Database/UpdateBy";
|
|
11
14
|
import {
|
|
@@ -16,6 +19,9 @@ import {
|
|
|
16
19
|
import TelemetryIngestSurface from "../../../Types/Telemetry/TelemetryIngestSurface";
|
|
17
20
|
import TelemetryIngestionKeyType from "../../../Types/Telemetry/TelemetryIngestionKeyType";
|
|
18
21
|
import PaymentRequiredException from "../../../Types/Exception/PaymentRequiredException";
|
|
22
|
+
import SubscriptionPlan, {
|
|
23
|
+
PlanType,
|
|
24
|
+
} from "../../../Types/Billing/SubscriptionPlan";
|
|
19
25
|
import ObjectID from "../../../Types/ObjectID";
|
|
20
26
|
import * as EnvironmentConfig from "../../../Server/EnvironmentConfig";
|
|
21
27
|
import {
|
|
@@ -101,6 +107,25 @@ function expectPaymentCheckedFor(project: ObjectID): void {
|
|
|
101
107
|
}
|
|
102
108
|
}
|
|
103
109
|
|
|
110
|
+
function useRealPaymentEligibility(plan: PlanType): void {
|
|
111
|
+
jest.mocked(PayAsYouGoBillingService.canUsePayAsYouGo).mockRestore();
|
|
112
|
+
PayAsYouGoBillingService.invalidate(projectId);
|
|
113
|
+
PayAsYouGoBillingService.invalidate(otherProjectId);
|
|
114
|
+
jest.spyOn(BillingService, "isBillingEnabled").mockReturnValue(true);
|
|
115
|
+
jest.spyOn(BillingService, "hasPaymentMethods").mockResolvedValue(false);
|
|
116
|
+
jest.spyOn(ProjectService, "findOneById").mockResolvedValue(
|
|
117
|
+
Object.assign(new Project(), {
|
|
118
|
+
paymentProviderPlanId: plan,
|
|
119
|
+
paymentProviderCustomerId: "cus_telemetry_project",
|
|
120
|
+
}),
|
|
121
|
+
);
|
|
122
|
+
jest
|
|
123
|
+
.spyOn(SubscriptionPlan, "getSubscriptionPlanById")
|
|
124
|
+
.mockReturnValue(
|
|
125
|
+
new SubscriptionPlan(plan, `${plan}_yearly`, plan, 0, 0, 0, 0),
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
104
129
|
beforeEach(() => {
|
|
105
130
|
jest.restoreAllMocks();
|
|
106
131
|
(EnvironmentConfig as { IsBillingEnabled: boolean }).IsBillingEnabled = true;
|
|
@@ -353,3 +378,109 @@ describe("HTTP telemetry admission integrates key resolution and billing", () =>
|
|
|
353
378
|
expect(TelemetryIngestionKeyService.markUsed).toHaveBeenCalledTimes(1);
|
|
354
379
|
});
|
|
355
380
|
});
|
|
381
|
+
|
|
382
|
+
describe("telemetry operations use the stored subscription plan for payment eligibility", () => {
|
|
383
|
+
describe.each([PlanType.Growth, PlanType.Scale, PlanType.Enterprise])(
|
|
384
|
+
"%s telemetry keys without a payment method",
|
|
385
|
+
(plan: PlanType) => {
|
|
386
|
+
test.each(Object.values(TelemetryIngestionKeyType))(
|
|
387
|
+
"allows creating a %s key",
|
|
388
|
+
async (keyType: TelemetryIngestionKeyType) => {
|
|
389
|
+
useRealPaymentEligibility(plan);
|
|
390
|
+
const input: CreateBy<TelemetryIngestionKey> = createInput();
|
|
391
|
+
input.data.keyType = keyType;
|
|
392
|
+
input.data.allowedOrigins = ["https://example.com"];
|
|
393
|
+
|
|
394
|
+
await expect(hooks.onBeforeCreate(input)).resolves.toBeDefined();
|
|
395
|
+
|
|
396
|
+
expect(ProjectService.findOneById).toHaveBeenCalledWith(
|
|
397
|
+
expect.objectContaining({ id: projectId }),
|
|
398
|
+
);
|
|
399
|
+
expect(BillingService.hasPaymentMethods).not.toHaveBeenCalled();
|
|
400
|
+
},
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
test("allows re-enabling a key using its stored project", async () => {
|
|
404
|
+
useRealPaymentEligibility(plan);
|
|
405
|
+
jest.spyOn(service, "findBy").mockResolvedValue([key(otherProjectId)]);
|
|
406
|
+
|
|
407
|
+
await expect(
|
|
408
|
+
hooks.onBeforeUpdate(updateInput({ isEnabled: true })),
|
|
409
|
+
).resolves.toBeDefined();
|
|
410
|
+
|
|
411
|
+
expect(ProjectService.findOneById).toHaveBeenCalledWith(
|
|
412
|
+
expect.objectContaining({ id: otherProjectId }),
|
|
413
|
+
);
|
|
414
|
+
expect(BillingService.hasPaymentMethods).not.toHaveBeenCalled();
|
|
415
|
+
});
|
|
416
|
+
},
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
test("still requires a payment method to create or re-enable Free telemetry keys", async () => {
|
|
420
|
+
useRealPaymentEligibility(PlanType.Free);
|
|
421
|
+
jest.spyOn(service, "findBy").mockResolvedValue([key()]);
|
|
422
|
+
|
|
423
|
+
await expect(hooks.onBeforeCreate(createInput())).rejects.toBeInstanceOf(
|
|
424
|
+
PaymentRequiredException,
|
|
425
|
+
);
|
|
426
|
+
await expect(
|
|
427
|
+
hooks.onBeforeUpdate(updateInput({ isEnabled: true })),
|
|
428
|
+
).rejects.toBeInstanceOf(PaymentRequiredException);
|
|
429
|
+
|
|
430
|
+
expect(BillingService.hasPaymentMethods).toHaveBeenCalledWith(
|
|
431
|
+
"cus_telemetry_project",
|
|
432
|
+
);
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
describe.each([
|
|
436
|
+
PlanType.Free,
|
|
437
|
+
PlanType.Growth,
|
|
438
|
+
PlanType.Scale,
|
|
439
|
+
PlanType.Enterprise,
|
|
440
|
+
])("%s HTTP telemetry without a payment method", (plan: PlanType) => {
|
|
441
|
+
test.each(Object.values(TelemetryIngestSurface))(
|
|
442
|
+
"applies plan eligibility before the %s handler",
|
|
443
|
+
async (surface: TelemetryIngestSurface) => {
|
|
444
|
+
useRealPaymentEligibility(plan);
|
|
445
|
+
const existingKey: TelemetryIngestionKey = key();
|
|
446
|
+
jest
|
|
447
|
+
.spyOn(TelemetryIngestionKeyService, "findOneBy")
|
|
448
|
+
.mockResolvedValue(existingKey);
|
|
449
|
+
jest
|
|
450
|
+
.spyOn(TelemetryIngestionKeyService, "markUsed")
|
|
451
|
+
.mockResolvedValue(undefined);
|
|
452
|
+
const request: ExpressRequest = {
|
|
453
|
+
headers: { "x-oneuptime-token": existingKey.secretKey!.toString() },
|
|
454
|
+
} as unknown as ExpressRequest;
|
|
455
|
+
const next: NextFunction = jest.fn() as unknown as NextFunction;
|
|
456
|
+
|
|
457
|
+
await TelemetryIngest.forSurface(surface)(
|
|
458
|
+
request,
|
|
459
|
+
{} as ExpressResponse,
|
|
460
|
+
next,
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
expect(next).toHaveBeenCalledTimes(1);
|
|
464
|
+
if (plan === PlanType.Free) {
|
|
465
|
+
expect(next).toHaveBeenCalledWith(
|
|
466
|
+
expect.any(PaymentRequiredException),
|
|
467
|
+
);
|
|
468
|
+
expect((request as TelemetryRequest).projectId).toBeUndefined();
|
|
469
|
+
expect(TelemetryIngestionKeyService.markUsed).not.toHaveBeenCalled();
|
|
470
|
+
expect(BillingService.hasPaymentMethods).toHaveBeenCalledWith(
|
|
471
|
+
"cus_telemetry_project",
|
|
472
|
+
);
|
|
473
|
+
} else {
|
|
474
|
+
expect(next).toHaveBeenCalledWith();
|
|
475
|
+
expect((request as TelemetryRequest).projectId.toString()).toBe(
|
|
476
|
+
projectId.toString(),
|
|
477
|
+
);
|
|
478
|
+
expect(TelemetryIngestionKeyService.markUsed).toHaveBeenCalledTimes(
|
|
479
|
+
1,
|
|
480
|
+
);
|
|
481
|
+
expect(BillingService.hasPaymentMethods).not.toHaveBeenCalled();
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
);
|
|
485
|
+
});
|
|
486
|
+
});
|
|
@@ -38,6 +38,7 @@ import NotificationRuleType from "../../../Types/NotificationRule/NotificationRu
|
|
|
38
38
|
import ObjectID from "../../../Types/ObjectID";
|
|
39
39
|
import UserNotificationEventType from "../../../Types/UserNotification/UserNotificationEventType";
|
|
40
40
|
import UserNotificationStatus from "../../../Types/UserNotification/UserNotificationStatus";
|
|
41
|
+
import UserType from "../../../Types/UserType";
|
|
41
42
|
import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
42
43
|
|
|
43
44
|
/*
|
|
@@ -616,6 +617,11 @@ describe("UserNotificationRule administrative write guards", () => {
|
|
|
616
617
|
* An API key has no user identity. If the widened create list ever admits
|
|
617
618
|
* one, "actor equals owner" is trivially false and must NOT be read as
|
|
618
619
|
* "nobody else involved, carry on".
|
|
620
|
+
*
|
|
621
|
+
* The fixture says userType API because an API key is the only actor-less
|
|
622
|
+
* caller that can reach this hook: DatabaseService.create now refuses a
|
|
623
|
+
* caller with no credentials at all (no userId, not an API key) with a
|
|
624
|
+
* 401 before any hook runs.
|
|
619
625
|
*/
|
|
620
626
|
stubs.teamMemberFind.mockResolvedValue(null as never);
|
|
621
627
|
|
|
@@ -623,7 +629,7 @@ describe("UserNotificationRule administrative write guards", () => {
|
|
|
623
629
|
hooks().onBeforeCreate(
|
|
624
630
|
createBy({
|
|
625
631
|
userId: VICTIM_USER_ID,
|
|
626
|
-
props: { tenantId: PROJECT_ID },
|
|
632
|
+
props: { tenantId: PROJECT_ID, userType: UserType.API },
|
|
627
633
|
channels: { userEmailId: METHOD_ID },
|
|
628
634
|
}),
|
|
629
635
|
),
|
|
@@ -631,10 +637,15 @@ describe("UserNotificationRule administrative write guards", () => {
|
|
|
631
637
|
});
|
|
632
638
|
|
|
633
639
|
test("a rule with neither an owner nor an actor is refused rather than written unowned", async () => {
|
|
640
|
+
/*
|
|
641
|
+
* Actor-less means an API key here, for the same reason as above: an
|
|
642
|
+
* anonymous caller is refused (401) by DatabaseService.create before
|
|
643
|
+
* this hook, so it never sees this 400.
|
|
644
|
+
*/
|
|
634
645
|
await expect(
|
|
635
646
|
hooks().onBeforeCreate(
|
|
636
647
|
createBy({
|
|
637
|
-
props: { tenantId: PROJECT_ID },
|
|
648
|
+
props: { tenantId: PROJECT_ID, userType: UserType.API },
|
|
638
649
|
channels: { userEmailId: METHOD_ID },
|
|
639
650
|
}),
|
|
640
651
|
),
|