@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,259 @@
|
|
|
1
|
+
import Incident from "../../../Models/DatabaseModels/Incident";
|
|
2
|
+
import Monitor from "../../../Models/DatabaseModels/Monitor";
|
|
3
|
+
import Project from "../../../Models/DatabaseModels/Project";
|
|
4
|
+
import IncidentService from "../../../Server/Services/IncidentService";
|
|
5
|
+
import MonitorService from "../../../Server/Services/MonitorService";
|
|
6
|
+
import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
7
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
8
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
9
|
+
import Permission, { UserPermission } from "../../../Types/Permission";
|
|
10
|
+
import PositiveNumber from "../../../Types/PositiveNumber";
|
|
11
|
+
import { getJestSpyOn } from "../../Spy";
|
|
12
|
+
import {
|
|
13
|
+
afterEach,
|
|
14
|
+
beforeEach,
|
|
15
|
+
describe,
|
|
16
|
+
expect,
|
|
17
|
+
jest,
|
|
18
|
+
test,
|
|
19
|
+
} from "@jest/globals";
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* PasswordHash has a known TS5.9 compile failure under ts-jest that breaks any
|
|
23
|
+
* suite whose import graph reaches it (see ApiKeyPermissionSecurity.test.ts).
|
|
24
|
+
* Nothing here touches password hashing; stub it before the service import
|
|
25
|
+
* graph drags it into compilation.
|
|
26
|
+
*/
|
|
27
|
+
jest.mock("../../../Server/Utils/PasswordHash", () => {
|
|
28
|
+
return {
|
|
29
|
+
__esModule: true,
|
|
30
|
+
default: class PasswordHashStub {},
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/*
|
|
35
|
+
* Cross-tenant write via the tenant RELATION (confused deputy).
|
|
36
|
+
*
|
|
37
|
+
* A tenant model declares its tenant twice — the scalar `projectId` column and
|
|
38
|
+
* the `project` @ManyToOne relation joined on that same column — and both are
|
|
39
|
+
* writable by an ordinary member on create. `DatabaseService.create` stamps
|
|
40
|
+
* only the scalar to `props.tenantId`; TypeORM then lets the relation object
|
|
41
|
+
* override the scalar join value on the INSERT, so a member of project A who
|
|
42
|
+
* posts `project: { _id: B }` writes the row into project B.
|
|
43
|
+
*
|
|
44
|
+
* `enforceTenantRelationMatchesScalar` rejects a tenant relation pointing at a
|
|
45
|
+
* different project and deletes it so the stamped scalar is the only thing
|
|
46
|
+
* that reaches the database. These tests drive the real `create()` pipeline
|
|
47
|
+
* (only the IO/validation neighbours that are orthogonal to tenancy are
|
|
48
|
+
* stubbed) and the guard directly for the update-shaped (plain object) input.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
const PROJECT_A: ObjectID = new ObjectID(
|
|
52
|
+
"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
|
|
53
|
+
);
|
|
54
|
+
const PROJECT_B: ObjectID = new ObjectID(
|
|
55
|
+
"bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
function userPermission(permission: Permission): UserPermission {
|
|
59
|
+
return {
|
|
60
|
+
permission,
|
|
61
|
+
labelIds: [],
|
|
62
|
+
isBlockPermission: false,
|
|
63
|
+
_type: "UserPermission",
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function memberProps(
|
|
68
|
+
tenantId: ObjectID = PROJECT_A,
|
|
69
|
+
): DatabaseCommonInteractionProps {
|
|
70
|
+
return {
|
|
71
|
+
userId: new ObjectID("dddddddd-dddd-4ddd-8ddd-dddddddddddd"),
|
|
72
|
+
tenantId,
|
|
73
|
+
ignoreHooks: true,
|
|
74
|
+
userGlobalAccessPermission: {
|
|
75
|
+
projectIds: [tenantId],
|
|
76
|
+
globalPermissions: [Permission.Public, Permission.User],
|
|
77
|
+
_type: "UserGlobalAccessPermission",
|
|
78
|
+
},
|
|
79
|
+
userTenantAccessPermission: {
|
|
80
|
+
[tenantId.toString()]: {
|
|
81
|
+
projectId: tenantId,
|
|
82
|
+
permissions: [userPermission(Permission.ProjectMember)],
|
|
83
|
+
_type: "UserTenantAccessPermission",
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function rootProps(): DatabaseCommonInteractionProps {
|
|
90
|
+
return { isRoot: true, ignoreHooks: true };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
type Target = {
|
|
94
|
+
name: string;
|
|
95
|
+
service: typeof MonitorService | typeof IncidentService;
|
|
96
|
+
build: () => Monitor | Incident;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const TARGETS: Array<Target> = [
|
|
100
|
+
{
|
|
101
|
+
name: "Monitor",
|
|
102
|
+
service: MonitorService,
|
|
103
|
+
build: () => {
|
|
104
|
+
const monitor: Monitor = new Monitor();
|
|
105
|
+
monitor.name = "guard-test";
|
|
106
|
+
return monitor;
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: "Incident",
|
|
111
|
+
service: IncidentService,
|
|
112
|
+
build: () => {
|
|
113
|
+
const incident: Incident = new Incident();
|
|
114
|
+
incident.title = "guard-test";
|
|
115
|
+
return incident;
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
function projectRelation(id: ObjectID): Project {
|
|
121
|
+
const project: Project = new Project();
|
|
122
|
+
project._id = id.toString();
|
|
123
|
+
return project;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
describe("DatabaseService tenant-relation cross-tenant write guard", () => {
|
|
127
|
+
describe.each(TARGETS)("$name create()", (target: Target) => {
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
129
|
+
const service: any = target.service;
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
131
|
+
let save: jest.Mock<(entity: any) => Promise<any>>;
|
|
132
|
+
|
|
133
|
+
beforeEach(() => {
|
|
134
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
135
|
+
save = jest.fn(async (entity: any) => {
|
|
136
|
+
return entity;
|
|
137
|
+
}) as any;
|
|
138
|
+
getJestSpyOn(service, "getRepository").mockReturnValue({
|
|
139
|
+
save,
|
|
140
|
+
} as never);
|
|
141
|
+
// Count-backed validators (unique/limit checks) must not hit Postgres.
|
|
142
|
+
getJestSpyOn(service, "countBy").mockResolvedValue(
|
|
143
|
+
new PositiveNumber(0) as never,
|
|
144
|
+
);
|
|
145
|
+
/*
|
|
146
|
+
* Required-field validation is orthogonal to the tenancy guard under
|
|
147
|
+
* test; keep it from failing on unrelated columns.
|
|
148
|
+
*/
|
|
149
|
+
getJestSpyOn(service, "checkRequiredFields").mockImplementation(((
|
|
150
|
+
data: unknown,
|
|
151
|
+
) => {
|
|
152
|
+
return data;
|
|
153
|
+
}) as never);
|
|
154
|
+
// Fire-and-forget side effects that would otherwise reach the network.
|
|
155
|
+
getJestSpyOn(service, "onTriggerWorkflow").mockResolvedValue(
|
|
156
|
+
undefined as never,
|
|
157
|
+
);
|
|
158
|
+
getJestSpyOn(service, "onTriggerRealtime").mockResolvedValue(
|
|
159
|
+
undefined as never,
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
afterEach(() => {
|
|
164
|
+
jest.restoreAllMocks();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("rejects a create whose project relation points at another project", async () => {
|
|
168
|
+
const data: Monitor | Incident = target.build();
|
|
169
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
170
|
+
(data as any).project = projectRelation(PROJECT_B);
|
|
171
|
+
|
|
172
|
+
await expect(
|
|
173
|
+
service.create({ data, props: memberProps(PROJECT_A) }),
|
|
174
|
+
).rejects.toThrow(BadDataException);
|
|
175
|
+
|
|
176
|
+
expect(save).not.toHaveBeenCalled();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("drops a matching project relation and persists under the request tenant only", async () => {
|
|
180
|
+
const data: Monitor | Incident = target.build();
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
182
|
+
(data as any).project = projectRelation(PROJECT_A);
|
|
183
|
+
|
|
184
|
+
await service.create({ data, props: memberProps(PROJECT_A) });
|
|
185
|
+
|
|
186
|
+
expect(save).toHaveBeenCalledTimes(1);
|
|
187
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
188
|
+
const saved: any = save.mock.calls[0]![0];
|
|
189
|
+
expect(saved.project).toBeUndefined();
|
|
190
|
+
expect(saved.projectId?.toString()).toBe(PROJECT_A.toString());
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test("leaves the project relation untouched for a root/internal caller", async () => {
|
|
194
|
+
const data: Monitor | Incident = target.build();
|
|
195
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
196
|
+
(data as any).project = projectRelation(PROJECT_B);
|
|
197
|
+
|
|
198
|
+
await service.create({ data, props: rootProps() });
|
|
199
|
+
|
|
200
|
+
expect(save).toHaveBeenCalledTimes(1);
|
|
201
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
202
|
+
const saved: any = save.mock.calls[0]![0];
|
|
203
|
+
expect(saved.project).toBeInstanceOf(Project);
|
|
204
|
+
expect(saved.project._id).toBe(PROJECT_B.toString());
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
/*
|
|
209
|
+
* The same guard runs on the update path, where the payload is a plain
|
|
210
|
+
* object (BaseAPI.updateItem deserializes rather than fromJSON'ing), so the
|
|
211
|
+
* relation arrives as `{ _id: ... }` rather than a Project instance.
|
|
212
|
+
*/
|
|
213
|
+
describe("enforceTenantRelationMatchesScalar (update-shaped input)", () => {
|
|
214
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
215
|
+
const guard: any = MonitorService;
|
|
216
|
+
|
|
217
|
+
test("throws when a plain-object project relation points at another project", () => {
|
|
218
|
+
const data: Record<string, unknown> = {
|
|
219
|
+
name: "x",
|
|
220
|
+
project: { _id: PROJECT_B.toString() },
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
expect(() => {
|
|
224
|
+
guard.enforceTenantRelationMatchesScalar(data, memberProps(PROJECT_A));
|
|
225
|
+
}).toThrow(BadDataException);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("strips a matching plain-object project relation", () => {
|
|
229
|
+
const data: Record<string, unknown> = {
|
|
230
|
+
name: "x",
|
|
231
|
+
project: { _id: PROJECT_A.toString() },
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
guard.enforceTenantRelationMatchesScalar(data, memberProps(PROJECT_A));
|
|
235
|
+
|
|
236
|
+
expect(data["project"]).toBeUndefined();
|
|
237
|
+
expect(data["name"]).toBe("x");
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
test("is a no-op when no project relation is supplied", () => {
|
|
241
|
+
const data: Record<string, unknown> = { name: "x" };
|
|
242
|
+
|
|
243
|
+
expect(() => {
|
|
244
|
+
guard.enforceTenantRelationMatchesScalar(data, memberProps(PROJECT_A));
|
|
245
|
+
}).not.toThrow();
|
|
246
|
+
expect(data).toEqual({ name: "x" });
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test("does not touch the relation for a root/internal caller", () => {
|
|
250
|
+
const data: Record<string, unknown> = {
|
|
251
|
+
project: { _id: PROJECT_B.toString() },
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
guard.enforceTenantRelationMatchesScalar(data, rootProps());
|
|
255
|
+
|
|
256
|
+
expect(data["project"]).toEqual({ _id: PROJECT_B.toString() });
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
});
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import ProbeService from "../../../Server/Services/ProbeService";
|
|
2
|
+
import CreateBy from "../../../Server/Types/Database/CreateBy";
|
|
3
|
+
import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
4
|
+
import Probe from "../../../Models/DatabaseModels/Probe";
|
|
5
|
+
import StartsWith from "../../../Types/BaseDatabase/StartsWith";
|
|
6
|
+
import NotNull from "../../../Types/BaseDatabase/NotNull";
|
|
7
|
+
import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
8
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
9
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
10
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
11
|
+
import Permission, {
|
|
12
|
+
UserPermission,
|
|
13
|
+
UserTenantAccessPermission,
|
|
14
|
+
} from "../../../Types/Permission";
|
|
15
|
+
import UserType from "../../../Types/UserType";
|
|
16
|
+
import { afterEach, describe, expect, jest, test } from "@jest/globals";
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
* Query operators belong in the `query` of a read/update, never in the `data`
|
|
20
|
+
* of a write. A request value shaped like a serialized operator, e.g.
|
|
21
|
+
* {"_type":"StartsWith","value":"a"} or {"_type":"NotNull"}, becomes a real
|
|
22
|
+
* operator instance: JSONFunctions.deserialize runs on every request body while
|
|
23
|
+
* DatabaseBaseModel._fromJSON builds the model, and the operator is assigned to
|
|
24
|
+
* the column unchanged.
|
|
25
|
+
*
|
|
26
|
+
* An operator is never a valid stored value, and one left on a write payload is
|
|
27
|
+
* also fed to the lookups built from that data (the uniqueness check, service
|
|
28
|
+
* hooks), where it turns an intended exact comparison into a pattern match.
|
|
29
|
+
* DatabaseService rejects such a write up front, before any hook or query runs.
|
|
30
|
+
* JSON columns are exempt - they legitimately hold arbitrary objects.
|
|
31
|
+
*
|
|
32
|
+
* The first two tests document the deserialization behaviour, which is
|
|
33
|
+
* unchanged; the last two pin the rejection and that ordinary writes still pass.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
37
|
+
"00000000-0000-4000-8000-00000000000a",
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const memberProps: (
|
|
41
|
+
permissions: Array<Permission>,
|
|
42
|
+
) => DatabaseCommonInteractionProps = (
|
|
43
|
+
permissions: Array<Permission>,
|
|
44
|
+
): DatabaseCommonInteractionProps => {
|
|
45
|
+
const tenantPermission: UserTenantAccessPermission = {
|
|
46
|
+
projectId: PROJECT_ID,
|
|
47
|
+
_type: "UserTenantAccessPermission",
|
|
48
|
+
permissions: permissions.map((permission: Permission): UserPermission => {
|
|
49
|
+
return {
|
|
50
|
+
_type: "UserPermission",
|
|
51
|
+
permission: permission,
|
|
52
|
+
labelIds: [],
|
|
53
|
+
isBlockPermission: false,
|
|
54
|
+
};
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
userId: new ObjectID("00000000-0000-4000-8000-000000000003"),
|
|
60
|
+
tenantId: PROJECT_ID,
|
|
61
|
+
userType: UserType.User,
|
|
62
|
+
userTenantAccessPermission: {
|
|
63
|
+
[PROJECT_ID.toString()]: tenantPermission,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
afterEach(() => {
|
|
69
|
+
jest.restoreAllMocks();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("Query operators supplied as write values", () => {
|
|
73
|
+
test("request body value {_type:StartsWith} deserializes into a StartsWith on a text column", () => {
|
|
74
|
+
const body: JSONObject = {
|
|
75
|
+
key: { _type: "StartsWith", value: "a" } as unknown as JSONObject,
|
|
76
|
+
name: "a probe",
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const probe: Probe = BaseModel.fromJSON<Probe>(body, Probe) as Probe;
|
|
80
|
+
|
|
81
|
+
expect(probe.key).toBeInstanceOf(StartsWith);
|
|
82
|
+
expect((probe.key as unknown as StartsWith<string>).toString()).toBe("a");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("request body value {_type:NotNull} deserializes into a NotNull operator", () => {
|
|
86
|
+
const body: JSONObject = {
|
|
87
|
+
key: { _type: "NotNull" } as unknown as JSONObject,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const probe: Probe = BaseModel.fromJSON<Probe>(body, Probe) as Probe;
|
|
91
|
+
expect(probe.key).toBeInstanceOf(NotNull);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("DatabaseService.create rejects an operator in write data before any lookup", async () => {
|
|
95
|
+
/*
|
|
96
|
+
* If the check regresses, the uniqueness check would run its countBy with
|
|
97
|
+
* the operator in the query; make that fail loudly instead.
|
|
98
|
+
*/
|
|
99
|
+
const countSpy: jest.SpyInstance = jest
|
|
100
|
+
.spyOn(ProbeService, "countBy")
|
|
101
|
+
.mockImplementation((() => {
|
|
102
|
+
throw new Error("countBy must not run for an operator-carrying create");
|
|
103
|
+
}) as never) as unknown as jest.SpyInstance;
|
|
104
|
+
const hookSpy: jest.SpyInstance = jest.spyOn(
|
|
105
|
+
ProbeService,
|
|
106
|
+
"onBeforeCreate" as never,
|
|
107
|
+
) as unknown as jest.SpyInstance;
|
|
108
|
+
|
|
109
|
+
const probe: Probe = new Probe();
|
|
110
|
+
(probe as unknown as { key: unknown }).key = new StartsWith("a");
|
|
111
|
+
probe.name = "a probe";
|
|
112
|
+
|
|
113
|
+
const createBy: CreateBy<Probe> = {
|
|
114
|
+
data: probe,
|
|
115
|
+
props: memberProps([Permission.CreateProjectProbe]),
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
await expect(ProbeService.create(createBy)).rejects.toBeInstanceOf(
|
|
119
|
+
BadDataException,
|
|
120
|
+
);
|
|
121
|
+
expect(hookSpy).not.toHaveBeenCalled();
|
|
122
|
+
expect(countSpy).not.toHaveBeenCalled();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("the operator check leaves an ordinary create untouched", () => {
|
|
126
|
+
/*
|
|
127
|
+
* The check must refuse operators without touching plain values. Call it
|
|
128
|
+
* directly - it is the choke point create()/update() run - and assert a
|
|
129
|
+
* normal payload passes while an operator is refused.
|
|
130
|
+
*/
|
|
131
|
+
const legit: Probe = new Probe();
|
|
132
|
+
legit.key = "a-real-plaintext-key";
|
|
133
|
+
legit.name = "a probe";
|
|
134
|
+
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
136
|
+
const service: any = ProbeService as any;
|
|
137
|
+
expect(() => {
|
|
138
|
+
service.rejectQueryOperatorsInData(legit);
|
|
139
|
+
}).not.toThrow();
|
|
140
|
+
|
|
141
|
+
const withOperator: Probe = new Probe();
|
|
142
|
+
(withOperator as unknown as { key: unknown }).key = new StartsWith("a");
|
|
143
|
+
expect(() => {
|
|
144
|
+
service.rejectQueryOperatorsInData(withOperator);
|
|
145
|
+
}).toThrow(BadDataException);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
@@ -2,15 +2,19 @@ import MonitorService from "../../../Server/Services/MonitorService";
|
|
|
2
2
|
import MonitorStatusService from "../../../Server/Services/MonitorStatusService";
|
|
3
3
|
import ProjectService from "../../../Server/Services/ProjectService";
|
|
4
4
|
import PayAsYouGoBillingService from "../../../Server/Services/PayAsYouGoBillingService";
|
|
5
|
+
import BillingService from "../../../Server/Services/BillingService";
|
|
5
6
|
import MonitorStepsProjectValidator from "../../../Server/Utils/Monitor/MonitorStepsProjectValidator";
|
|
6
7
|
import Monitor from "../../../Models/DatabaseModels/Monitor";
|
|
7
8
|
import MonitorStatus from "../../../Models/DatabaseModels/MonitorStatus";
|
|
9
|
+
import Project from "../../../Models/DatabaseModels/Project";
|
|
8
10
|
import CreateBy from "../../../Server/Types/Database/CreateBy";
|
|
9
11
|
import UpdateBy from "../../../Server/Types/Database/UpdateBy";
|
|
10
12
|
import MonitorType from "../../../Types/Monitor/MonitorType";
|
|
11
13
|
import ObjectID from "../../../Types/ObjectID";
|
|
12
14
|
import PositiveNumber from "../../../Types/PositiveNumber";
|
|
13
|
-
import {
|
|
15
|
+
import SubscriptionPlan, {
|
|
16
|
+
PlanType,
|
|
17
|
+
} from "../../../Types/Billing/SubscriptionPlan";
|
|
14
18
|
import PaymentRequiredException from "../../../Types/Exception/PaymentRequiredException";
|
|
15
19
|
import * as EnvironmentConfig from "../../../Server/EnvironmentConfig";
|
|
16
20
|
import {
|
|
@@ -89,6 +93,30 @@ function expectPaymentCheckedFor(project: ObjectID): void {
|
|
|
89
93
|
}
|
|
90
94
|
}
|
|
91
95
|
|
|
96
|
+
function useRealPaymentEligibility(plan: PlanType): void {
|
|
97
|
+
jest.mocked(PayAsYouGoBillingService.canUsePayAsYouGo).mockRestore();
|
|
98
|
+
PayAsYouGoBillingService.invalidate(projectId);
|
|
99
|
+
PayAsYouGoBillingService.invalidate(otherProjectId);
|
|
100
|
+
jest.spyOn(BillingService, "isBillingEnabled").mockReturnValue(true);
|
|
101
|
+
jest.spyOn(BillingService, "hasPaymentMethods").mockResolvedValue(false);
|
|
102
|
+
jest.spyOn(BillingService, "getSubscription");
|
|
103
|
+
jest.spyOn(ProjectService, "findOneById").mockResolvedValue(
|
|
104
|
+
Object.assign(new Project(), {
|
|
105
|
+
paymentProviderPlanId: plan,
|
|
106
|
+
paymentProviderCustomerId: "cus_monitor_project",
|
|
107
|
+
}),
|
|
108
|
+
);
|
|
109
|
+
jest
|
|
110
|
+
.spyOn(SubscriptionPlan, "getSubscriptionPlanById")
|
|
111
|
+
.mockReturnValue(
|
|
112
|
+
new SubscriptionPlan(plan, `${plan}_yearly`, plan, 0, 0, 0, 0),
|
|
113
|
+
);
|
|
114
|
+
jest.spyOn(ProjectService, "getCurrentPlan").mockResolvedValue({
|
|
115
|
+
plan,
|
|
116
|
+
isSubscriptionUnpaid: false,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
92
120
|
beforeEach(() => {
|
|
93
121
|
jest.restoreAllMocks();
|
|
94
122
|
(EnvironmentConfig as { IsBillingEnabled: boolean }).IsBillingEnabled = true;
|
|
@@ -300,3 +328,89 @@ describe("monitor update payment admission", () => {
|
|
|
300
328
|
expect(MonitorService.findBy).not.toHaveBeenCalled();
|
|
301
329
|
});
|
|
302
330
|
});
|
|
331
|
+
|
|
332
|
+
describe("monitor operations use the stored subscription plan for payment eligibility", () => {
|
|
333
|
+
test.each([PlanType.Growth, PlanType.Scale, PlanType.Enterprise])(
|
|
334
|
+
"allows active monitor creation on %s without a payment method",
|
|
335
|
+
async (plan: PlanType) => {
|
|
336
|
+
useRealPaymentEligibility(plan);
|
|
337
|
+
|
|
338
|
+
await expect(
|
|
339
|
+
hooks.onBeforeCreate(createInput(MonitorType.Website)),
|
|
340
|
+
).resolves.toBeDefined();
|
|
341
|
+
|
|
342
|
+
expect(ProjectService.findOneById).toHaveBeenCalledWith(
|
|
343
|
+
expect.objectContaining({ id: projectId }),
|
|
344
|
+
);
|
|
345
|
+
expect(BillingService.hasPaymentMethods).not.toHaveBeenCalled();
|
|
346
|
+
expect(BillingService.getSubscription).not.toHaveBeenCalled();
|
|
347
|
+
expect(MonitorService.countBy).not.toHaveBeenCalled();
|
|
348
|
+
},
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
describe.each([PlanType.Growth, PlanType.Scale, PlanType.Enterprise])(
|
|
352
|
+
"%s monitor updates without a payment method",
|
|
353
|
+
(plan: PlanType) => {
|
|
354
|
+
test.each([
|
|
355
|
+
{ disableActiveMonitoring: false },
|
|
356
|
+
{ monitorType: MonitorType.API },
|
|
357
|
+
])(
|
|
358
|
+
"allows the billable update %j",
|
|
359
|
+
async (data: UpdateBy<Monitor>["data"]) => {
|
|
360
|
+
useRealPaymentEligibility(plan);
|
|
361
|
+
jest
|
|
362
|
+
.spyOn(MonitorService, "findBy")
|
|
363
|
+
.mockResolvedValue([
|
|
364
|
+
storedMonitor(otherProjectId, MonitorType.Website),
|
|
365
|
+
]);
|
|
366
|
+
|
|
367
|
+
await expect(
|
|
368
|
+
hooks.onBeforeUpdate(updateInput(data)),
|
|
369
|
+
).resolves.toBeDefined();
|
|
370
|
+
|
|
371
|
+
expect(ProjectService.findOneById).toHaveBeenCalledWith(
|
|
372
|
+
expect.objectContaining({ id: otherProjectId }),
|
|
373
|
+
);
|
|
374
|
+
expect(BillingService.hasPaymentMethods).not.toHaveBeenCalled();
|
|
375
|
+
},
|
|
376
|
+
);
|
|
377
|
+
},
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
test("still rejects Free monitor creation and re-enabling without a payment method", async () => {
|
|
381
|
+
useRealPaymentEligibility(PlanType.Free);
|
|
382
|
+
jest
|
|
383
|
+
.spyOn(MonitorService, "findBy")
|
|
384
|
+
.mockResolvedValue([storedMonitor(projectId, MonitorType.Website)]);
|
|
385
|
+
|
|
386
|
+
await expect(
|
|
387
|
+
hooks.onBeforeCreate(createInput(MonitorType.Website)),
|
|
388
|
+
).rejects.toBeInstanceOf(PaymentRequiredException);
|
|
389
|
+
await expect(
|
|
390
|
+
hooks.onBeforeUpdate(updateInput({ disableActiveMonitoring: false })),
|
|
391
|
+
).rejects.toBeInstanceOf(PaymentRequiredException);
|
|
392
|
+
|
|
393
|
+
expect(BillingService.hasPaymentMethods).toHaveBeenCalledWith(
|
|
394
|
+
"cus_monitor_project",
|
|
395
|
+
);
|
|
396
|
+
expect(MonitorStatusService.findOneBy).not.toHaveBeenCalled();
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
test.each([PlanType.Growth, PlanType.Scale, PlanType.Enterprise])(
|
|
400
|
+
"retains the separate unpaid %s subscription check after exempting payment setup",
|
|
401
|
+
async (plan: PlanType) => {
|
|
402
|
+
useRealPaymentEligibility(plan);
|
|
403
|
+
jest.spyOn(ProjectService, "getCurrentPlan").mockResolvedValue({
|
|
404
|
+
plan,
|
|
405
|
+
isSubscriptionUnpaid: true,
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
await expect(
|
|
409
|
+
hooks.onBeforeCreate(createInput(MonitorType.Website)),
|
|
410
|
+
).rejects.toThrow("subscription is unpaid");
|
|
411
|
+
|
|
412
|
+
expect(BillingService.hasPaymentMethods).not.toHaveBeenCalled();
|
|
413
|
+
expect(MonitorStatusService.findOneBy).not.toHaveBeenCalled();
|
|
414
|
+
},
|
|
415
|
+
);
|
|
416
|
+
});
|