@oneuptime/common 12.0.8 → 12.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.ts +1 -1
- package/Models/AnalyticsModels/MetricItemAggMV1mByService.ts +1 -1
- package/Models/DatabaseModels/AIConversation.ts +32 -0
- package/Models/DatabaseModels/AIConversationMessage.ts +41 -0
- package/Models/DatabaseModels/AlertEpisodeMember.ts +27 -0
- package/Models/DatabaseModels/IncidentEpisodeMember.ts +28 -0
- package/Models/DatabaseModels/Index.ts +12 -4
- package/Models/DatabaseModels/{TelemetryEntity.ts → InventoryItem.ts} +139 -9
- package/Models/DatabaseModels/InventoryItemCustomField.ts +434 -0
- package/Models/DatabaseModels/{TelemetryEntityRelationship.ts → InventoryItemRelationship.ts} +8 -8
- package/Models/DatabaseModels/NetworkDevice.ts +141 -0
- package/Models/DatabaseModels/NetworkDeviceLink.ts +699 -0
- package/Models/DatabaseModels/NetworkDeviceLinkRule.ts +467 -0
- package/Models/DatabaseModels/NetworkTopologySuppression.ts +429 -0
- package/Models/DatabaseModels/OnCallDutyPolicyFeed.ts +9 -0
- package/Models/DatabaseModels/Project.ts +78 -0
- package/Models/DatabaseModels/UserCall.ts +42 -0
- package/Models/DatabaseModels/UserEmail.ts +44 -0
- package/Models/DatabaseModels/UserNotificationRule.ts +425 -55
- package/Models/DatabaseModels/UserOnCallLogTimeline.ts +24 -2
- package/Models/DatabaseModels/UserPush.ts +49 -0
- package/Models/DatabaseModels/UserSMS.ts +43 -0
- package/Models/DatabaseModels/UserTelegram.ts +59 -0
- package/Models/DatabaseModels/UserWebhook.ts +52 -0
- package/Models/DatabaseModels/UserWhatsApp.ts +41 -0
- package/Models/DatabaseModels/WorkflowVariable.ts +12 -0
- package/Server/API/AIChatAPI.ts +315 -1
- package/Server/API/DashboardAPI.ts +217 -1
- package/Server/API/OnCallReadinessAPI.ts +841 -0
- package/Server/API/TeamComplianceAPI.ts +69 -17
- package/Server/API/TelemetryAPI.ts +220 -12
- package/Server/EnvironmentConfig.ts +52 -0
- package/Server/Infrastructure/Postgres/DataSourceOptions.ts +22 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.ts +4 -4
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.ts +5 -5
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786625176831-AddMonitoringMethodToNetworkDevice.ts +35 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786634985763-AddNetworkDeviceLink.ts +82 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786639512056-AddNetworkDeviceLinkRule.ts +91 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786639972982-AddNetworkTopologySuppression.ts +47 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786800000000-RenameTelemetryEntityToInventoryItem.ts +255 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786900000000-AddInventoryItemArchiveAndCustomFields.ts +107 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787000000000-AddOnCallNotificationFallbackColumns.ts +90 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787100000000-AddAIConversationPageContext.ts +39 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787200000000-AddAIChatMessageFeedback.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787300000000-AddEpisodeMemberNotifyIndexes.ts +59 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +20 -0
- package/Server/Infrastructure/Queue.ts +78 -13
- package/Server/Middleware/PublicDashboardRateLimit.ts +593 -0
- package/Server/Services/AIService.ts +7 -0
- package/Server/Services/AlertEpisodeStateTimelineService.ts +29 -0
- package/Server/Services/AlertSeverityService.ts +63 -0
- package/Server/Services/DashboardService.ts +9 -10
- package/Server/Services/DatabaseService.ts +32 -2
- package/Server/Services/IncidentEpisodeStateTimelineService.ts +29 -0
- package/Server/Services/IncidentSeverityService.ts +76 -0
- package/Server/Services/Index.ts +12 -4
- package/Server/Services/InventoryItemCustomFieldService.ts +9 -0
- package/Server/Services/{TelemetryEntityRelationshipService.ts → InventoryItemRelationshipService.ts} +4 -4
- package/Server/Services/{TelemetryEntityService.ts → InventoryItemService.ts} +89 -20
- package/Server/Services/LogAggregationService.ts +45 -8
- package/Server/Services/MetricAggregationService.ts +121 -0
- package/Server/Services/MetricService.ts +7 -7
- package/Server/Services/NetworkDeviceLinkRuleService.ts +10 -0
- package/Server/Services/NetworkDeviceLinkService.ts +84 -0
- package/Server/Services/NetworkDeviceService.ts +140 -0
- package/Server/Services/NetworkSiteService.ts +77 -25
- package/Server/Services/NetworkTopologySuppressionService.ts +84 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +41 -29
- package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +8 -0
- package/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.ts +62 -13
- package/Server/Services/OnCallDutyPolicyScheduleService.ts +61 -1
- package/Server/Services/OnCallNotificationAlertingService.ts +742 -0
- package/Server/Services/OnCallReadinessService.ts +2803 -0
- package/Server/Services/OnCallSetupReminderService.ts +955 -0
- package/Server/Services/ProfileAggregationService.ts +123 -0
- package/Server/Services/StatusPageService.ts +9 -10
- package/Server/Services/TeamComplianceService.ts +429 -252
- package/Server/Services/UserCallService.ts +26 -1
- package/Server/Services/UserEmailService.ts +26 -1
- package/Server/Services/UserNotificationRuleAdminService.ts +1183 -0
- package/Server/Services/UserNotificationRuleService.ts +3812 -333
- package/Server/Services/UserOnCallLogService.ts +561 -48
- package/Server/Services/UserPushService.ts +29 -0
- package/Server/Services/UserService.ts +11 -0
- package/Server/Services/UserSmsService.ts +26 -1
- package/Server/Services/UserTelegramService.ts +24 -1
- package/Server/Services/UserWebhookService.ts +28 -1
- package/Server/Services/UserWhatsAppService.ts +24 -1
- package/Server/Types/Database/Permissions/BasePermission.ts +19 -0
- package/Server/Types/Database/Permissions/CreatePermission.ts +164 -0
- package/Server/Types/Database/Permissions/OwnerOnlyColumnPermission.ts +340 -0
- package/Server/Types/Database/Permissions/QueryPermission.ts +48 -0
- package/Server/Types/Database/Permissions/TenantPermission.ts +8 -1
- package/Server/Types/Workflow/Components/API/Delete.ts +1 -1
- package/Server/Types/Workflow/Components/API/Get.ts +1 -1
- package/Server/Types/Workflow/Components/API/Patch.ts +1 -1
- package/Server/Types/Workflow/Components/API/Post.ts +1 -1
- package/Server/Types/Workflow/Components/API/Put.ts +1 -1
- package/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.ts +29 -5
- package/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.ts +18 -10
- package/Server/Types/Workflow/Components/BaseModel/ModelArguments.ts +55 -0
- package/Server/Types/Workflow/Components/Conditions/IfElse.ts +3 -17
- package/Server/Types/Workflow/Components/Email.ts +25 -7
- package/Server/Types/Workflow/Components/JavaScript.ts +10 -3
- package/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.ts +1 -1
- package/Server/Utils/AI/Chat/ChatAgentRunner.ts +643 -48
- package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +32 -3
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +20 -6
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +7 -0
- package/Server/Utils/AI/Toolbox/AIActionTools.ts +2 -2
- package/Server/Utils/AI/Toolbox/AIMetaTools.ts +863 -0
- package/Server/Utils/AI/Toolbox/AlertTools.ts +177 -15
- package/Server/Utils/AI/Toolbox/IncidentTools.ts +191 -10
- package/Server/Utils/AI/Toolbox/Index.ts +48 -0
- package/Server/Utils/AI/Toolbox/MonitorTools.ts +298 -11
- package/Server/Utils/AI/Toolbox/NoteWriteTools.ts +295 -0
- package/Server/Utils/AI/Toolbox/OnCallTools.ts +1246 -0
- package/Server/Utils/AI/Toolbox/RunbookTools.ts +424 -0
- package/Server/Utils/AI/Toolbox/SloTools.ts +456 -0
- package/Server/Utils/AI/Toolbox/StatusPageTools.ts +559 -0
- package/Server/Utils/AI/Toolbox/TeamTools.ts +327 -0
- package/Server/Utils/AI/Toolbox/TimelineTools.ts +615 -0
- package/Server/Utils/AI/Toolbox/WorkflowProbeTools.ts +664 -0
- package/Server/Utils/ClientIp.ts +221 -0
- package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +47 -0
- package/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.ts +163 -0
- package/Server/Utils/Dashboard/PublicDashboardSloWidget.ts +147 -0
- package/Server/Utils/Express.ts +12 -17
- package/Server/Utils/LLM/LLMService.ts +85 -8
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +204 -10
- package/Server/Utils/SSRFProtection.ts +98 -23
- package/Server/Utils/StartServer.ts +12 -3
- package/Server/Utils/Telemetry/EntityRegistry.ts +205 -18
- package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +25 -25
- package/Server/Utils/Telemetry/TelemetryEntity.ts +160 -52
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +7 -3
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +2146 -0
- package/Tests/App/Dashboard/CreateWorkflowModal.test.tsx +561 -0
- package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +2470 -0
- package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +1897 -0
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3606 -0
- package/Tests/App/Dashboard/OnCallRulesDeleteGuard.test.tsx +784 -0
- package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +1119 -0
- package/Tests/App/Dashboard/SloWidgetFetching.test.tsx +531 -0
- package/Tests/App/Dashboard/UserSettingsSetupChecklistModel.test.ts +1312 -0
- package/Tests/App/Dashboard/UserSettingsSetupChecklistPage.test.tsx +1390 -0
- package/Tests/Models/InventoryItemModel.test.ts +174 -0
- package/Tests/Models/InventoryItemNaming.test.ts +302 -0
- package/Tests/Server/API/AIChatCancelAndFeedback.test.ts +437 -0
- package/Tests/Server/API/DashboardPublicRateLimit.test.ts +659 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +18 -0
- package/Tests/Server/API/DashboardPublicSloAPI.test.ts +880 -0
- package/Tests/Server/API/Helpers.ts +24 -15
- package/Tests/Server/API/OnCallReadinessAPI.test.ts +2680 -0
- package/Tests/Server/API/OnCallSetupReminderAPI.test.ts +915 -0
- package/Tests/Server/Infrastructure/Postgres/EpisodeMemberNotifyIndexesMigration.test.ts +533 -0
- package/Tests/Server/Infrastructure/Postgres/InventoryItemArchiveMigration.test.ts +213 -0
- package/Tests/Server/Infrastructure/Postgres/RenameInventoryItemMigration.test.ts +432 -0
- package/Tests/Server/Infrastructure/Queue.test.ts +293 -0
- package/Tests/Server/Middleware/PublicDashboardRateLimit.test.ts +1645 -0
- package/Tests/Server/Services/AdminRuleEditGuards.test.ts +2848 -0
- package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +1393 -0
- package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +1802 -0
- package/Tests/Server/Services/EpisodeStateTimelineNote.test.ts +304 -0
- package/Tests/Server/Services/InventoryItemDisplayName.test.ts +339 -0
- package/Tests/Server/Services/{TelemetryEntityManualCreate.test.ts → InventoryItemManualCreate.test.ts} +27 -27
- package/Tests/Server/Services/IpAllowlistSpoofing.test.ts +450 -0
- package/Tests/Server/Services/LogAggregationService.test.ts +235 -1
- package/Tests/Server/Services/MetricAggregationService.test.ts +231 -0
- package/Tests/Server/Services/MetricEntityMVKeyParity.test.ts +80 -29
- package/Tests/Server/Services/MetricServiceAggregate.test.ts +30 -30
- package/Tests/Server/Services/NetworkSiteService.test.ts +18 -3
- package/Tests/Server/Services/NotificationChannelEventCoverage.test.ts +1728 -0
- package/Tests/Server/Services/NotificationDeletionImpact.test.ts +2402 -0
- package/Tests/Server/Services/OnCallDutyPolicyExecutionLogTimelineGapFeed.test.ts +394 -0
- package/Tests/Server/Services/OnCallNotificationFallback.test.ts +1744 -0
- package/Tests/Server/Services/OnCallReadinessService.test.ts +4295 -0
- package/Tests/Server/Services/OnCallSetupReminder.test.ts +1272 -0
- package/Tests/Server/Services/OnCallWeeklyReadinessDigest.test.ts +1021 -0
- package/Tests/Server/Services/ProfileAggregationService.test.ts +296 -0
- package/Tests/Server/Services/SeverityCreationRuleBackfill.test.ts +1536 -0
- package/Tests/Server/Services/SeverityRuleBackfill.test.ts +1818 -0
- package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +1845 -0
- package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +1394 -0
- package/Tests/Server/Services/UserNotificationRuleDefaultCreation.test.ts +1166 -0
- package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +1468 -0
- package/Tests/Server/Services/UserOnCallLogNoNotificationRules.test.ts +1457 -0
- package/Tests/Server/Types/Database/Permissions/AdminNotificationRuleAccess.test.ts +1546 -0
- package/Tests/Server/Types/Database/Permissions/CreateOwnershipScoping.test.ts +529 -0
- package/Tests/Server/Types/Database/Permissions/OwnerOnlyColumns.test.ts +1219 -0
- package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +1089 -0
- package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +2 -1
- package/Tests/Server/Types/Workflow/Components/BaseModelDatabaseComponents.test.ts +190 -0
- package/Tests/Server/Types/Workflow/Components/ChatWebhookComponents.test.ts +44 -14
- package/Tests/Server/Types/Workflow/Components/Email.test.ts +151 -0
- package/Tests/Server/Types/Workflow/Components/IfElse.test.ts +98 -0
- package/Tests/Server/Types/Workflow/Components/JavaScript.test.ts +51 -0
- package/Tests/Server/Utils/AI/AIMetaTools.test.ts +586 -0
- package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +582 -0
- package/Tests/Server/Utils/AI/ChatAgentRunner.test.ts +726 -0
- package/Tests/Server/Utils/AI/IncidentToolsFilters.test.ts +315 -0
- package/Tests/Server/Utils/AI/LLMServiceStopReason.test.ts +314 -0
- package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +26 -3
- package/Tests/Server/Utils/AI/NoteWriteTools.test.ts +268 -0
- package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +169 -0
- package/Tests/Server/Utils/AI/OnCallTools.test.ts +664 -0
- package/Tests/Server/Utils/AI/RunbookTools.test.ts +325 -0
- package/Tests/Server/Utils/AI/SloTools.test.ts +306 -0
- package/Tests/Server/Utils/AI/StatusPageTools.test.ts +391 -0
- package/Tests/Server/Utils/AI/TeamTools.test.ts +257 -0
- package/Tests/Server/Utils/AI/TimelineTools.test.ts +472 -0
- package/Tests/Server/Utils/AI/WorkflowProbeTools.test.ts +428 -0
- package/Tests/Server/Utils/ClientIp.test.ts +438 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +171 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.test.ts +383 -0
- package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +23 -25
- package/Tests/Server/Utils/MicrosoftTeamsWebhookUrlValidation.test.ts +6 -0
- package/Tests/Server/Utils/Monitor/Criteria/DnssecMonitorCriteria.test.ts +307 -0
- package/Tests/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.test.ts +468 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorTelemetryDeepLinks.test.ts +460 -0
- package/Tests/Server/Utils/ResponseRateLimitStatusCodes.test.ts +137 -0
- package/Tests/Server/Utils/SSRFProtectionBypasses.test.ts +40 -8
- package/Tests/Server/Utils/SSRFProtectionUserInfo.test.ts +351 -0
- package/Tests/Server/Utils/Telemetry/EntityRegistryRetirement.test.ts +531 -0
- package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +15 -15
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +356 -39
- package/Tests/Types/IP/IP.test.ts +263 -0
- package/Tests/Types/IP/IPWhitelist.test.ts +197 -0
- package/Tests/Types/IP/IPv6.test.ts +12 -1
- package/Tests/Types/Monitor/SnmpOid.test.ts +64 -0
- package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +110 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilMergeAudit.test.ts +106 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilMergeDifferential.test.ts +511 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleCoverageEndToEnd.test.ts +489 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleCoverageGapTolerance.test.ts +479 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleCoverageState.test.ts +822 -0
- package/Tests/Types/Telemetry/EntityTypeGroups.test.ts +6 -6
- package/Tests/Types/Workflow/BaseModelComponents.test.ts +429 -0
- package/Tests/Types/Workflow/Components/BaseModel.test.ts +225 -0
- package/Tests/Types/Workflow/IntegrationCredentialMetadata.test.ts +100 -0
- package/Tests/Types/Workflow/TemplateSyntax.test.ts +112 -0
- package/Tests/Types/Workflow/Templates.test.ts +916 -101
- package/Tests/UI/Components/ActiveFilterChipsOpenRoute.test.tsx +82 -0
- package/Tests/UI/Components/ComponentsModal.test.tsx +564 -7
- package/Tests/UI/Components/KeyboardShortcut.test.tsx +95 -0
- package/Tests/UI/Components/LogDetailsPanelCrossSignal.test.tsx +448 -0
- package/Tests/UI/Components/LogsTableCrossLinks.test.tsx +263 -0
- package/Tests/UI/Components/PendingProjectInvitations.test.tsx +913 -0
- package/Tests/UI/Components/SimpleLogViewer.test.tsx +228 -0
- package/Tests/UI/Components/TableRowSelectability.test.tsx +312 -0
- package/Tests/UI/Components/Workflow/GraphLint.test.ts +72 -0
- package/Tests/UI/Components/Workflow/GraphLintSummary.test.ts +755 -0
- package/Tests/UI/Components/Workflow/ModelColumnEditor.test.ts +242 -7
- package/Tests/UI/Components/Workflow/ModelColumnEditorServerContract.test.ts +15 -7
- package/Tests/UI/Components/Workflow/ModelSchema.test.ts +242 -28
- package/Tests/UI/Components/Workflow/RunStatusWatcher.test.ts +59 -1
- package/Tests/UI/Components/Workflow/StepTraceViewer.test.tsx +256 -0
- package/Tests/UI/Components/Workflow/UseRunWatch.test.tsx +665 -0
- package/Tests/UI/Components/Workflow/WorkflowIssuesModal.test.tsx +485 -0
- package/Tests/UI/Components/Workflow/WorkflowLogModal.test.tsx +478 -0
- package/Tests/UI/Components/Workflow/WorkflowStatusBar.test.tsx +379 -0
- package/Tests/UI/EsbuildConfig.test.ts +607 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +5 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +11 -4
- package/Tests/UI/Utils/ModelAPICreateMiscData.test.ts +94 -0
- package/Tests/UI/Utils/Platform.test.ts +147 -0
- package/Tests/UI/Utils/ProjectInvitationDisplay.test.ts +357 -0
- package/Tests/Utils/Monitor/NetworkDeviceLinkRuleUtil.test.ts +198 -0
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +487 -0
- package/Tests/Utils/Telemetry/CrossSignalScope.test.ts +698 -0
- package/Tests/__mocks__/bullmq.js +55 -0
- package/Types/AI/AIChatMessageStatus.ts +8 -1
- package/Types/AI/AIChatTypes.ts +12 -0
- package/Types/Database/AccessControl/OwnerOnlyColumn.ts +88 -0
- package/Types/Exception/ExceptionCode.ts +2 -0
- package/Types/Exception/ServiceUnavailableException.ts +8 -0
- package/Types/Exception/TooManyRequestsException.ts +8 -0
- package/Types/IP/IP.ts +93 -47
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +49 -3
- package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +55 -0
- package/Types/OnCallDutyPolicy/Layer.ts +203 -149
- package/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus.ts +13 -0
- package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +155 -10
- package/Types/Permission.ts +193 -0
- package/Types/Telemetry/EntityRelationshipType.ts +1 -1
- package/Types/Telemetry/EntitySource.ts +1 -1
- package/Types/Telemetry/EntityType.ts +1 -1
- package/Types/Telemetry/EntityTypeGroups.ts +1 -1
- package/Types/Workflow/Components/BaseModel.ts +75 -29
- package/Types/Workflow/Components/Discord.ts +1 -0
- package/Types/Workflow/Components/Email.ts +12 -3
- package/Types/Workflow/Components/JavaScript.ts +7 -0
- package/Types/Workflow/Components/MicrosoftTeams.ts +3 -2
- package/Types/Workflow/Components/Slack.ts +1 -0
- package/Types/Workflow/Components/Telegram.ts +1 -0
- package/Types/Workflow/TemplateSyntax.ts +44 -0
- package/Types/Workflow/Templates.ts +2097 -45
- package/UI/Components/Calendar/Calendar.css +43 -0
- package/UI/Components/Calendar/Calendar.tsx +8 -0
- package/UI/Components/Card/Card.tsx +2 -2
- package/UI/Components/Checkbox/Checkbox.tsx +16 -0
- package/UI/Components/Dictionary/Dictionary.tsx +48 -9
- package/UI/Components/FormModal/BasicFormModal.tsx +2 -1
- package/UI/Components/Header/HeaderIconDropdownButton.tsx +53 -3
- package/UI/Components/Input/Input.tsx +1 -0
- package/UI/Components/KeyboardShortcut/KeyboardKey.ts +185 -0
- package/UI/Components/KeyboardShortcut/KeyboardShortcut.tsx +87 -0
- package/UI/Components/LogsViewer/LogsViewer.tsx +28 -0
- package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +31 -0
- package/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.tsx +18 -18
- package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +363 -14
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +11 -0
- package/UI/Components/LogsViewer/components/LogsTable.tsx +155 -12
- package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +29 -0
- package/UI/Components/LogsViewer/types.ts +23 -0
- package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +9 -2
- package/UI/Components/Navbar/NavBarMenuModal.tsx +15 -30
- package/UI/Components/ProjectInvitations/PendingProjectInvitations.tsx +442 -0
- package/UI/Components/SimpleLogViewer/SimpleLogViewer.tsx +23 -1
- package/UI/Components/Table/Table.tsx +49 -16
- package/UI/Components/Table/TableBody.tsx +53 -28
- package/UI/Components/Table/TableHeader.tsx +13 -0
- package/UI/Components/Table/TableRow.tsx +58 -26
- package/UI/Components/Workflow/ArgumentsForm.tsx +155 -9
- package/UI/Components/Workflow/ComponentReturnValueViewer.tsx +26 -0
- package/UI/Components/Workflow/ComponentSettingsModal.tsx +10 -1
- package/UI/Components/Workflow/ComponentValuePickerModal.tsx +135 -7
- package/UI/Components/Workflow/ComponentsModal.tsx +116 -22
- package/UI/Components/Workflow/DocumentationViewer.tsx +59 -9
- package/UI/Components/Workflow/GraphLint.ts +42 -5
- package/UI/Components/Workflow/GraphLintSummary.ts +390 -0
- package/UI/Components/Workflow/ModelColumnEditor.tsx +154 -22
- package/UI/Components/Workflow/ModelSchema.ts +115 -33
- package/UI/Components/Workflow/RunStatusWatcher.ts +1 -1
- package/UI/Components/Workflow/StepTraceViewer.tsx +1 -1
- package/UI/Components/Workflow/UseRunWatch.ts +212 -0
- package/UI/Components/Workflow/VariableModal.tsx +6 -2
- package/UI/Components/Workflow/Workflow.tsx +49 -3
- package/UI/Components/Workflow/WorkflowIssuesModal.tsx +255 -0
- package/UI/Components/Workflow/WorkflowLogModal.tsx +128 -0
- package/UI/Components/Workflow/WorkflowStatusBar.tsx +224 -0
- package/UI/Utils/AIChatExport/ConversationMarkdown.ts +10 -0
- package/UI/Utils/ModelAPI/ModelAPI.ts +7 -1
- package/UI/Utils/Platform.ts +149 -0
- package/UI/Utils/ProjectInvitationDisplay.ts +118 -0
- package/UI/esbuild-config.js +22 -1
- package/Utils/Monitor/NetworkDeviceLinkRuleUtil.ts +187 -0
- package/Utils/Monitor/NetworkTopologyUtil.ts +888 -164
- package/Utils/Telemetry/CrossSignalScope.ts +502 -0
- package/Utils/Telemetry/EntityKey.ts +5 -5
- package/Utils/Telemetry/EntityRelationship.ts +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js +1 -1
- package/build/dist/Models/DatabaseModels/AIConversation.js +32 -0
- package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AIConversationMessage.js +42 -0
- package/build/dist/Models/DatabaseModels/AIConversationMessage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js +28 -0
- package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js +29 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +12 -4
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/{TelemetryEntity.js → InventoryItem.js} +167 -31
- package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -0
- package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js +454 -0
- package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js.map +1 -0
- package/build/dist/Models/DatabaseModels/{TelemetryEntityRelationship.js → InventoryItemRelationship.js} +27 -27
- package/build/dist/Models/DatabaseModels/InventoryItemRelationship.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +141 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js +719 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js +475 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkTopologySuppression.js +446 -0
- package/build/dist/Models/DatabaseModels/NetworkTopologySuppression.js.map +1 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyFeed.js +9 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +80 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserCall.js +46 -2
- package/build/dist/Models/DatabaseModels/UserCall.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserEmail.js +48 -2
- package/build/dist/Models/DatabaseModels/UserEmail.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserNotificationRule.js +424 -55
- package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +24 -2
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserPush.js +51 -1
- package/build/dist/Models/DatabaseModels/UserPush.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserSMS.js +47 -2
- package/build/dist/Models/DatabaseModels/UserSMS.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserTelegram.js +65 -3
- package/build/dist/Models/DatabaseModels/UserTelegram.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWebhook.js +56 -2
- package/build/dist/Models/DatabaseModels/UserWebhook.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWhatsApp.js +45 -2
- package/build/dist/Models/DatabaseModels/UserWhatsApp.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js +12 -0
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
- package/build/dist/Server/API/AIChatAPI.js +237 -1
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +165 -13
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallReadinessAPI.js +599 -0
- package/build/dist/Server/API/OnCallReadinessAPI.js.map +1 -0
- package/build/dist/Server/API/TeamComplianceAPI.js +68 -9
- package/build/dist/Server/API/TeamComplianceAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +129 -18
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +45 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js +4 -4
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786625176831-AddMonitoringMethodToNetworkDevice.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786625176831-AddMonitoringMethodToNetworkDevice.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786634985763-AddNetworkDeviceLink.js +39 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786634985763-AddNetworkDeviceLink.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786639512056-AddNetworkDeviceLinkRule.js +38 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786639512056-AddNetworkDeviceLinkRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786639972982-AddNetworkTopologySuppression.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786639972982-AddNetworkTopologySuppression.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786800000000-RenameTelemetryEntityToInventoryItem.js +150 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786800000000-RenameTelemetryEntityToInventoryItem.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786900000000-AddInventoryItemArchiveAndCustomFields.js +57 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786900000000-AddInventoryItemArchiveAndCustomFields.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787000000000-AddOnCallNotificationFallbackColumns.js +69 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787000000000-AddOnCallNotificationFallbackColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787100000000-AddAIConversationPageContext.js +32 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787100000000-AddAIConversationPageContext.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787200000000-AddAIChatMessageFeedback.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787200000000-AddAIChatMessageFeedback.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787300000000-AddEpisodeMemberNotifyIndexes.js +48 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787300000000-AddEpisodeMemberNotifyIndexes.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Queue.js +72 -13
- package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
- package/build/dist/Server/Middleware/PublicDashboardRateLimit.js +399 -0
- package/build/dist/Server/Middleware/PublicDashboardRateLimit.js.map +1 -0
- package/build/dist/Server/Services/AIService.js +1 -0
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeStateTimelineService.js +24 -3
- package/build/dist/Server/Services/AlertEpisodeStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/AlertSeverityService.js +54 -0
- package/build/dist/Server/Services/AlertSeverityService.js.map +1 -1
- package/build/dist/Server/Services/DashboardService.js +10 -9
- package/build/dist/Server/Services/DashboardService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +24 -2
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +24 -3
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentSeverityService.js +67 -0
- package/build/dist/Server/Services/IncidentSeverityService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +12 -4
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemCustomFieldService.js +9 -0
- package/build/dist/Server/Services/InventoryItemCustomFieldService.js.map +1 -0
- package/build/dist/Server/Services/{TelemetryEntityRelationshipService.js → InventoryItemRelationshipService.js} +6 -6
- package/build/dist/Server/Services/InventoryItemRelationshipService.js.map +1 -0
- package/build/dist/Server/Services/{TelemetryEntityService.js → InventoryItemService.js} +68 -23
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -0
- package/build/dist/Server/Services/LogAggregationService.js +27 -8
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricAggregationService.js +80 -0
- package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricService.js +6 -6
- package/build/dist/Server/Services/MetricService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLinkRuleService.js +9 -0
- package/build/dist/Server/Services/NetworkDeviceLinkRuleService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceLinkService.js +71 -0
- package/build/dist/Server/Services/NetworkDeviceLinkService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceService.js +113 -0
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteService.js +53 -13
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
- package/build/dist/Server/Services/NetworkTopologySuppressionService.js +85 -0
- package/build/dist/Server/Services/NetworkTopologySuppressionService.js.map +1 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +48 -32
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +8 -0
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js +51 -12
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +57 -13
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallNotificationAlertingService.js +548 -0
- package/build/dist/Server/Services/OnCallNotificationAlertingService.js.map +1 -0
- package/build/dist/Server/Services/OnCallReadinessService.js +1961 -0
- package/build/dist/Server/Services/OnCallReadinessService.js.map +1 -0
- package/build/dist/Server/Services/OnCallSetupReminderService.js +738 -0
- package/build/dist/Server/Services/OnCallSetupReminderService.js.map +1 -0
- package/build/dist/Server/Services/ProfileAggregationService.js +68 -4
- package/build/dist/Server/Services/ProfileAggregationService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +11 -10
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/TeamComplianceService.js +312 -160
- package/build/dist/Server/Services/TeamComplianceService.js.map +1 -1
- package/build/dist/Server/Services/UserCallService.js +24 -1
- package/build/dist/Server/Services/UserCallService.js.map +1 -1
- package/build/dist/Server/Services/UserEmailService.js +24 -1
- package/build/dist/Server/Services/UserEmailService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleAdminService.js +858 -0
- package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationRuleService.js +2830 -175
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallLogService.js +488 -43
- package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
- package/build/dist/Server/Services/UserPushService.js +26 -0
- package/build/dist/Server/Services/UserPushService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +10 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Services/UserSmsService.js +24 -1
- package/build/dist/Server/Services/UserSmsService.js.map +1 -1
- package/build/dist/Server/Services/UserTelegramService.js +22 -1
- package/build/dist/Server/Services/UserTelegramService.js.map +1 -1
- package/build/dist/Server/Services/UserWebhookService.js +25 -1
- package/build/dist/Server/Services/UserWebhookService.js.map +1 -1
- package/build/dist/Server/Services/UserWhatsAppService.js +22 -1
- package/build/dist/Server/Services/UserWhatsAppService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js +12 -1
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +126 -0
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerOnlyColumnPermission.js +254 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerOnlyColumnPermission.js.map +1 -0
- package/build/dist/Server/Types/Database/Permissions/QueryPermission.js +47 -2
- package/build/dist/Server/Types/Database/Permissions/QueryPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +7 -0
- package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Get.js +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Post.js +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Put.js +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js +21 -5
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js +14 -10
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js +31 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Conditions/IfElse.js +3 -9
- package/build/dist/Server/Types/Workflow/Components/Conditions/IfElse.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Email.js +15 -4
- package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/JavaScript.js +7 -2
- package/build/dist/Server/Types/Workflow/Components/JavaScript.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js +1 -1
- package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +514 -56
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +20 -3
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +19 -6
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +7 -0
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js +2 -2
- package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/AIMetaTools.js +692 -0
- package/build/dist/Server/Utils/AI/Toolbox/AIMetaTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +148 -12
- package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js +157 -10
- package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/Index.js +37 -0
- package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/MonitorTools.js +259 -14
- package/build/dist/Server/Utils/AI/Toolbox/MonitorTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/NoteWriteTools.js +235 -0
- package/build/dist/Server/Utils/AI/Toolbox/NoteWriteTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +1000 -0
- package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/RunbookTools.js +356 -0
- package/build/dist/Server/Utils/AI/Toolbox/RunbookTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +394 -0
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/StatusPageTools.js +465 -0
- package/build/dist/Server/Utils/AI/Toolbox/StatusPageTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/TeamTools.js +280 -0
- package/build/dist/Server/Utils/AI/Toolbox/TeamTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js +527 -0
- package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/WorkflowProbeTools.js +548 -0
- package/build/dist/Server/Utils/AI/Toolbox/WorkflowProbeTools.js.map +1 -0
- package/build/dist/Server/Utils/ClientIp.js +137 -0
- package/build/dist/Server/Utils/ClientIp.js.map +1 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +38 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
- package/build/dist/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.js +89 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.js.map +1 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardSloWidget.js +77 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardSloWidget.js.map +1 -0
- package/build/dist/Server/Utils/Express.js +12 -12
- package/build/dist/Server/Utils/Express.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +70 -7
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +121 -11
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +82 -21
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +12 -4
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +165 -18
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +11 -11
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +122 -47
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +7 -3
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/AI/AIChatMessageStatus.js +8 -1
- package/build/dist/Types/AI/AIChatMessageStatus.js.map +1 -1
- package/build/dist/Types/AI/AIChatTypes.js +12 -0
- package/build/dist/Types/AI/AIChatTypes.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +60 -0
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -0
- package/build/dist/Types/Exception/ExceptionCode.js +2 -0
- package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
- package/build/dist/Types/Exception/ServiceUnavailableException.js +8 -0
- package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -0
- package/build/dist/Types/Exception/TooManyRequestsException.js +8 -0
- package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -0
- package/build/dist/Types/IP/IP.js +87 -43
- package/build/dist/Types/IP/IP.js.map +1 -1
- package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +50 -0
- package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/Layer.js +186 -123
- package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus.js +13 -0
- package/build/dist/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +105 -11
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -1
- package/build/dist/Types/Permission.js +174 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Telemetry/EntityRelationshipType.js +1 -1
- package/build/dist/Types/Telemetry/EntitySource.js +1 -1
- package/build/dist/Types/Telemetry/EntityType.js +1 -1
- package/build/dist/Types/Telemetry/EntityTypeGroups.js +1 -1
- package/build/dist/Types/Telemetry/EntityTypeGroups.js.map +1 -1
- package/build/dist/Types/Workflow/Components/BaseModel.js +66 -28
- package/build/dist/Types/Workflow/Components/BaseModel.js.map +1 -1
- package/build/dist/Types/Workflow/Components/Discord.js +1 -0
- package/build/dist/Types/Workflow/Components/Discord.js.map +1 -1
- package/build/dist/Types/Workflow/Components/Email.js +12 -3
- package/build/dist/Types/Workflow/Components/Email.js.map +1 -1
- package/build/dist/Types/Workflow/Components/JavaScript.js +7 -0
- package/build/dist/Types/Workflow/Components/JavaScript.js.map +1 -1
- package/build/dist/Types/Workflow/Components/MicrosoftTeams.js +3 -2
- package/build/dist/Types/Workflow/Components/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/Workflow/Components/Slack.js +1 -0
- package/build/dist/Types/Workflow/Components/Slack.js.map +1 -1
- package/build/dist/Types/Workflow/Components/Telegram.js +1 -0
- package/build/dist/Types/Workflow/Components/Telegram.js.map +1 -1
- package/build/dist/Types/Workflow/TemplateSyntax.js +12 -0
- package/build/dist/Types/Workflow/TemplateSyntax.js.map +1 -1
- package/build/dist/Types/Workflow/Templates.js +1931 -38
- package/build/dist/Types/Workflow/Templates.js.map +1 -1
- package/build/dist/UI/Components/Calendar/Calendar.js +1 -1
- package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
- package/build/dist/UI/Components/Checkbox/Checkbox.js +1 -1
- package/build/dist/UI/Components/Checkbox/Checkbox.js.map +1 -1
- package/build/dist/UI/Components/Dictionary/Dictionary.js +25 -11
- package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
- package/build/dist/UI/Components/FormModal/BasicFormModal.js.map +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +27 -4
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +1 -0
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/KeyboardShortcut/KeyboardKey.js +163 -0
- package/build/dist/UI/Components/KeyboardShortcut/KeyboardKey.js.map +1 -0
- package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcut.js +47 -0
- package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcut.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +4 -4
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +11 -1
- package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js +10 -8
- package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +227 -14
- package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +5 -0
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsTable.js +69 -5
- package/build/dist/UI/Components/LogsViewer/components/LogsTable.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +8 -0
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/types.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +9 -2
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +8 -21
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Components/ProjectInvitations/PendingProjectInvitations.js +251 -0
- package/build/dist/UI/Components/ProjectInvitations/PendingProjectInvitations.js.map +1 -0
- package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js +9 -2
- package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js.map +1 -1
- package/build/dist/UI/Components/Table/Table.js +27 -15
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableBody.js +24 -18
- package/build/dist/UI/Components/Table/TableBody.js.map +1 -1
- package/build/dist/UI/Components/Table/TableHeader.js +9 -1
- package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +29 -21
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js +130 -12
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js +10 -1
- package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentSettingsModal.js +4 -4
- package/build/dist/UI/Components/Workflow/ComponentSettingsModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentValuePickerModal.js +57 -7
- package/build/dist/UI/Components/Workflow/ComponentValuePickerModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentsModal.js +53 -18
- package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/DocumentationViewer.js +19 -6
- package/build/dist/UI/Components/Workflow/DocumentationViewer.js.map +1 -1
- package/build/dist/UI/Components/Workflow/GraphLint.js +33 -4
- package/build/dist/UI/Components/Workflow/GraphLint.js.map +1 -1
- package/build/dist/UI/Components/Workflow/GraphLintSummary.js +231 -0
- package/build/dist/UI/Components/Workflow/GraphLintSummary.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +116 -21
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ModelSchema.js +72 -34
- package/build/dist/UI/Components/Workflow/ModelSchema.js.map +1 -1
- package/build/dist/UI/Components/Workflow/RunStatusWatcher.js +1 -1
- package/build/dist/UI/Components/Workflow/RunStatusWatcher.js.map +1 -1
- package/build/dist/UI/Components/Workflow/StepTraceViewer.js +1 -1
- package/build/dist/UI/Components/Workflow/StepTraceViewer.js.map +1 -1
- package/build/dist/UI/Components/Workflow/UseRunWatch.js +123 -0
- package/build/dist/UI/Components/Workflow/UseRunWatch.js.map +1 -0
- package/build/dist/UI/Components/Workflow/VariableModal.js +3 -2
- package/build/dist/UI/Components/Workflow/VariableModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/Workflow.js +41 -1
- package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
- package/build/dist/UI/Components/Workflow/WorkflowIssuesModal.js +99 -0
- package/build/dist/UI/Components/Workflow/WorkflowIssuesModal.js.map +1 -0
- package/build/dist/UI/Components/Workflow/WorkflowLogModal.js +56 -0
- package/build/dist/UI/Components/Workflow/WorkflowLogModal.js.map +1 -0
- package/build/dist/UI/Components/Workflow/WorkflowStatusBar.js +92 -0
- package/build/dist/UI/Components/Workflow/WorkflowStatusBar.js.map +1 -0
- package/build/dist/UI/Utils/AIChatExport/ConversationMarkdown.js +9 -0
- package/build/dist/UI/Utils/AIChatExport/ConversationMarkdown.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/Platform.js +118 -0
- package/build/dist/UI/Utils/Platform.js.map +1 -0
- package/build/dist/UI/Utils/ProjectInvitationDisplay.js +106 -0
- package/build/dist/UI/Utils/ProjectInvitationDisplay.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js +108 -0
- package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +642 -136
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/Telemetry/CrossSignalScope.js +328 -0
- package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -0
- package/build/dist/Utils/Telemetry/EntityKey.js +5 -5
- package/build/dist/Utils/Telemetry/EntityRelationship.js +1 -1
- package/jest.config.json +1 -0
- package/package.json +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryEntity.js.map +0 -1
- package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js.map +0 -1
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +0 -1
- package/build/dist/Server/Services/TelemetryEntityService.js.map +0 -1
|
@@ -0,0 +1,1089 @@
|
|
|
1
|
+
import TeamMember from "../../../../../Models/DatabaseModels/TeamMember";
|
|
2
|
+
import UserCall from "../../../../../Models/DatabaseModels/UserCall";
|
|
3
|
+
import UserEmail from "../../../../../Models/DatabaseModels/UserEmail";
|
|
4
|
+
import UserNotificationRule from "../../../../../Models/DatabaseModels/UserNotificationRule";
|
|
5
|
+
import UserPush from "../../../../../Models/DatabaseModels/UserPush";
|
|
6
|
+
import UserSMS from "../../../../../Models/DatabaseModels/UserSMS";
|
|
7
|
+
import UserTelegram from "../../../../../Models/DatabaseModels/UserTelegram";
|
|
8
|
+
import UserWebhook from "../../../../../Models/DatabaseModels/UserWebhook";
|
|
9
|
+
import UserWhatsApp from "../../../../../Models/DatabaseModels/UserWhatsApp";
|
|
10
|
+
import BaseModel from "../../../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
11
|
+
import DatabaseRequestType from "../../../../../Server/Types/BaseDatabase/DatabaseRequestType";
|
|
12
|
+
import TenantPermission from "../../../../../Server/Types/Database/Permissions/TenantPermission";
|
|
13
|
+
import Query from "../../../../../Server/Types/Database/Query";
|
|
14
|
+
import NotEqual from "../../../../../Types/BaseDatabase/NotEqual";
|
|
15
|
+
import DatabaseCommonInteractionProps from "../../../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
16
|
+
import ColumnAccessControl from "../../../../../Types/Database/AccessControl/ColumnAccessControl";
|
|
17
|
+
import TableAccessControl from "../../../../../Types/Database/AccessControl/TableAccessControl";
|
|
18
|
+
import CurrentUserCanAccessRecordBy from "../../../../../Types/Database/CurrentUserCanAccessRecordBy";
|
|
19
|
+
import TableColumn from "../../../../../Types/Database/TableColumn";
|
|
20
|
+
import TableColumnType from "../../../../../Types/Database/TableColumnType";
|
|
21
|
+
import TenantColumn from "../../../../../Types/Database/TenantColumn";
|
|
22
|
+
import NotAuthorizedException from "../../../../../Types/Exception/NotAuthorizedException";
|
|
23
|
+
import ObjectID from "../../../../../Types/ObjectID";
|
|
24
|
+
import Permission from "../../../../../Types/Permission";
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
* WHAT THIS FILE PINS
|
|
28
|
+
*
|
|
29
|
+
* On-call notification configuration - the rules themselves plus every channel
|
|
30
|
+
* they can fire through (email, SMS, call, push, WhatsApp, Telegram, webhook) -
|
|
31
|
+
* is row-scoped to its owner by one mechanism:
|
|
32
|
+
*
|
|
33
|
+
* @TableAccessControl({ ... [Permission.CurrentUser] ... })
|
|
34
|
+
* @CurrentUserCanAccessRecordBy("userId")
|
|
35
|
+
*
|
|
36
|
+
* TenantPermission.isAccessGrantedOnlyByCurrentUser() returns true whenever
|
|
37
|
+
* Permission.CurrentUser is the ONLY permission the caller holds that also
|
|
38
|
+
* appears in the model's table access control list. When it does,
|
|
39
|
+
* addCurrentUserScopeToQuery() rewrites the query to `userId = me`, and throws
|
|
40
|
+
* NotAuthorizedException outright if the caller had explicitly named somebody
|
|
41
|
+
* else. The FIRST group below is the standing proof that this still holds for a
|
|
42
|
+
* plain member on all eight models.
|
|
43
|
+
*
|
|
44
|
+
* GAP D in Internal/Roadmap/OnCallNotificationReadiness.md was the consequence
|
|
45
|
+
* for everybody else: a Project ADMIN was treated identically to a plain member
|
|
46
|
+
* on these tables, because ProjectAdmin appeared in none of these lists and so
|
|
47
|
+
* never landed in the intersection. There was no query an admin could issue
|
|
48
|
+
* that returned another user's notification configuration - not to audit it,
|
|
49
|
+
* not to repair it, not to see why a page went unanswered.
|
|
50
|
+
*
|
|
51
|
+
* IT WAS CLOSED ON THE RULE TABLE AND ONLY THERE. That boundary is the whole
|
|
52
|
+
* design and this file exists to keep it from being erased in either direction:
|
|
53
|
+
*
|
|
54
|
+
* - UserNotificationRule widens on ALL FOUR verbs. An administrator may read
|
|
55
|
+
* a member's rules, repair them, delete them, and provision one for a
|
|
56
|
+
* member who has none.
|
|
57
|
+
*
|
|
58
|
+
* - The SEVEN METHOD MODELS widen on NOTHING. All four lists are
|
|
59
|
+
* [CurrentUser], so an administrator is force-scoped onto their own rows
|
|
60
|
+
* there and is rejected outright for naming somebody else, on every verb -
|
|
61
|
+
* indistinguishable from a plain member.
|
|
62
|
+
*
|
|
63
|
+
* The read half of those seven WAS widened at one point, and reverting it is
|
|
64
|
+
* the most load-bearing fact in this file. The table scope is not one gate
|
|
65
|
+
* among several on these models; it is the only one. Every column on them
|
|
66
|
+
* declares `read: [Permission.CurrentUser]`, and that list is intersected by
|
|
67
|
+
* NAME against a permission set that always contains the auto-granted
|
|
68
|
+
* CurrentUser, so on its own it admits every authenticated caller. What made it
|
|
69
|
+
* mean "owner only" was the ownership predicate this file is about. Widening
|
|
70
|
+
* the table read deleted the predicate and with it the only row scope in the
|
|
71
|
+
* path; the column-level guard written to contain that was then walked past by
|
|
72
|
+
* nested relation selects, by `query` filters it never inspected, and by sort
|
|
73
|
+
* columns appended to the select after it had run.
|
|
74
|
+
*
|
|
75
|
+
* The administrator did not lose the diagnosis. OnCallReadinessService answers
|
|
76
|
+
* "can this colleague be paged" as root and returns ReadinessMethod
|
|
77
|
+
* { methodId, methodType, maskedIdentifier, isVerified }, masked server-side by
|
|
78
|
+
* the one code path that holds the raw value. methodId is a foreign key rather
|
|
79
|
+
* than a secret, so a rule can be pointed at a method without the method's row
|
|
80
|
+
* ever being read - which is exactly the capability the widening was reaching
|
|
81
|
+
* for.
|
|
82
|
+
*
|
|
83
|
+
* Row scoping is only half of what the rule-table widening moved, and the half
|
|
84
|
+
* this file does NOT cover. A nested relation select issued against an
|
|
85
|
+
* admin-wide read of UserNotificationRule reaches the method row without
|
|
86
|
+
* passing through the method table's list at all. That path is asserted
|
|
87
|
+
* end-to-end in AdminNotificationRuleAccess.test.ts; the column-list assertions
|
|
88
|
+
* at the bottom of this file are necessary but nowhere near sufficient on their
|
|
89
|
+
* own.
|
|
90
|
+
*
|
|
91
|
+
* Two further groups exist to keep the MECHANISM legible independently of the
|
|
92
|
+
* production decorators, so a future change cannot make the two agree by
|
|
93
|
+
* accident:
|
|
94
|
+
*
|
|
95
|
+
* - TeamMember carries the very same @CurrentUserCanAccessRecordBy("userId")
|
|
96
|
+
* decorator and has always listed ProjectOwner/ProjectAdmin in its read
|
|
97
|
+
* list. It is force-scoped for a member and unscoped for an admin. The
|
|
98
|
+
* ownership decorator was therefore never the thing scoping admins out -
|
|
99
|
+
* the absent permission entry was, which is why the rule table's fix is an
|
|
100
|
+
* entry in a list rather than a new gate, and why the seven methods stay
|
|
101
|
+
* scoped purely by having no such entry.
|
|
102
|
+
*
|
|
103
|
+
* - AdminReadableNotificationRuleModel below isolates the same shape on a
|
|
104
|
+
* throwaway class, with read and update widened and create and delete left
|
|
105
|
+
* alone. It demonstrates that the lift is granted PER OPERATION on a class
|
|
106
|
+
* whose lists match no shipping model, so the framework guarantee survives
|
|
107
|
+
* any future edit to a production one.
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
/*
|
|
111
|
+
* A throwaway stand-in for a user-scoped model, carrying ProjectAdmin on read
|
|
112
|
+
* and update only: same tenant column and same ownership column as the
|
|
113
|
+
* production models, but a combination of verbs that none of them use.
|
|
114
|
+
*
|
|
115
|
+
* It is deliberately not a copy of any shipping model - not of the rule table,
|
|
116
|
+
* whose four lists are all widened, and not of the seven methods, whose four
|
|
117
|
+
* lists are all closed. Its job is to pin the mechanism - the scope lifts for
|
|
118
|
+
* the operations whose list names a real permission and holds for the ones
|
|
119
|
+
* whose list does not - so that the production assertions above it are testing
|
|
120
|
+
* the models rather than re-testing the framework.
|
|
121
|
+
*/
|
|
122
|
+
@TenantColumn("projectId")
|
|
123
|
+
@TableAccessControl({
|
|
124
|
+
create: [Permission.CurrentUser],
|
|
125
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
126
|
+
update: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
127
|
+
delete: [Permission.CurrentUser],
|
|
128
|
+
})
|
|
129
|
+
@CurrentUserCanAccessRecordBy("userId")
|
|
130
|
+
class AdminReadableNotificationRuleModel extends BaseModel {
|
|
131
|
+
@ColumnAccessControl({
|
|
132
|
+
create: [Permission.CurrentUser],
|
|
133
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
134
|
+
update: [],
|
|
135
|
+
})
|
|
136
|
+
@TableColumn({
|
|
137
|
+
type: TableColumnType.ObjectID,
|
|
138
|
+
title: "Project ID",
|
|
139
|
+
})
|
|
140
|
+
public projectId?: ObjectID = undefined;
|
|
141
|
+
|
|
142
|
+
@ColumnAccessControl({
|
|
143
|
+
create: [Permission.CurrentUser],
|
|
144
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
145
|
+
update: [],
|
|
146
|
+
})
|
|
147
|
+
@TableColumn({
|
|
148
|
+
type: TableColumnType.ObjectID,
|
|
149
|
+
title: "User ID",
|
|
150
|
+
})
|
|
151
|
+
public userId?: ObjectID = undefined;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
type ModelTypeUnderTest = { new (): BaseModel };
|
|
155
|
+
|
|
156
|
+
/*
|
|
157
|
+
* The seven channels a rule can fire through. They are seven copies of one
|
|
158
|
+
* decorator shape, so every method assertion runs against all seven rather than
|
|
159
|
+
* against a representative one - a widening applied to one of them is exactly
|
|
160
|
+
* the kind of thing that survives review.
|
|
161
|
+
*/
|
|
162
|
+
const NOTIFICATION_METHOD_MODELS: Array<ModelTypeUnderTest> = [
|
|
163
|
+
UserEmail,
|
|
164
|
+
UserSMS,
|
|
165
|
+
UserCall,
|
|
166
|
+
UserPush,
|
|
167
|
+
UserWhatsApp,
|
|
168
|
+
UserTelegram,
|
|
169
|
+
UserWebhook,
|
|
170
|
+
];
|
|
171
|
+
|
|
172
|
+
/*
|
|
173
|
+
* Every model that makes up a user's on-call notification configuration.
|
|
174
|
+
*
|
|
175
|
+
* All eight behave identically for a plain member, which is what the first
|
|
176
|
+
* group asserts over this list. They diverge only in what an ADMINISTRATOR
|
|
177
|
+
* sees, so the admin-facing groups below name UserNotificationRule separately
|
|
178
|
+
* and iterate NOTIFICATION_METHOD_MODELS for the seven that stay closed.
|
|
179
|
+
*/
|
|
180
|
+
const NOTIFICATION_CONFIG_MODELS: Array<ModelTypeUnderTest> = [
|
|
181
|
+
UserNotificationRule,
|
|
182
|
+
...NOTIFICATION_METHOD_MODELS,
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
const ROW_SCOPED_REQUEST_TYPES: Array<DatabaseRequestType> = [
|
|
186
|
+
DatabaseRequestType.Read,
|
|
187
|
+
DatabaseRequestType.Update,
|
|
188
|
+
DatabaseRequestType.Delete,
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
/*
|
|
192
|
+
* The permissions the rule table gained, spelled out here rather than imported
|
|
193
|
+
* from the model. A test that reads the model's own constant would assert that
|
|
194
|
+
* the model equals itself; naming them independently means a change to a
|
|
195
|
+
* shipping list has to be re-stated deliberately in a test.
|
|
196
|
+
*
|
|
197
|
+
* On the seven method models these names appear only inside a `not.toContain`.
|
|
198
|
+
*/
|
|
199
|
+
const ADMIN_READ_GRANTS: Array<Permission> = [
|
|
200
|
+
Permission.ProjectOwner,
|
|
201
|
+
Permission.ProjectAdmin,
|
|
202
|
+
Permission.ReadProjectUserNotificationRule,
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
const ADMIN_WRITE_GRANTS: Array<Permission> = [
|
|
206
|
+
Permission.ProjectOwner,
|
|
207
|
+
Permission.ProjectAdmin,
|
|
208
|
+
Permission.EditProjectUserNotificationRule,
|
|
209
|
+
];
|
|
210
|
+
|
|
211
|
+
const projectId: ObjectID = ObjectID.generate();
|
|
212
|
+
const callerUserId: ObjectID = ObjectID.generate();
|
|
213
|
+
const otherUserId: ObjectID = ObjectID.generate();
|
|
214
|
+
|
|
215
|
+
/*
|
|
216
|
+
* A plain project member. No tenant role at all - the permission machinery
|
|
217
|
+
* auto-grants Public and CurrentUser to any request that carries a userId.
|
|
218
|
+
*/
|
|
219
|
+
function makeMemberProps(): DatabaseCommonInteractionProps {
|
|
220
|
+
return {
|
|
221
|
+
userId: callerUserId,
|
|
222
|
+
tenantId: projectId,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/*
|
|
227
|
+
* A caller holding Permission.ProjectAdmin for this tenant. This is the highest
|
|
228
|
+
* ordinary role in a project short of ProjectOwner.
|
|
229
|
+
*/
|
|
230
|
+
function makeAdminProps(): DatabaseCommonInteractionProps {
|
|
231
|
+
return {
|
|
232
|
+
userId: callerUserId,
|
|
233
|
+
tenantId: projectId,
|
|
234
|
+
userTenantAccessPermission: {
|
|
235
|
+
[projectId.toString()]: {
|
|
236
|
+
projectId: projectId,
|
|
237
|
+
permissions: [
|
|
238
|
+
{
|
|
239
|
+
permission: Permission.ProjectAdmin,
|
|
240
|
+
labelIds: [],
|
|
241
|
+
isBlockPermission: false,
|
|
242
|
+
_type: "UserPermission",
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
_type: "UserTenantAccessPermission",
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
describe("notification config models are row-scoped to their owner", () => {
|
|
252
|
+
it.each(NOTIFICATION_CONFIG_MODELS)(
|
|
253
|
+
"forces %p reads, updates and deletes onto the member's own rows",
|
|
254
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
255
|
+
for (const requestType of ROW_SCOPED_REQUEST_TYPES) {
|
|
256
|
+
const query: Query<BaseModel> =
|
|
257
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
258
|
+
modelType,
|
|
259
|
+
{},
|
|
260
|
+
null,
|
|
261
|
+
makeMemberProps(),
|
|
262
|
+
requestType,
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
expect((query as any).userId?.toString()).toBe(callerUserId.toString());
|
|
266
|
+
expect((query as any).projectId?.toString()).toBe(projectId.toString());
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
it.each(NOTIFICATION_CONFIG_MODELS)(
|
|
272
|
+
"rejects a member who explicitly names another user in a %p query",
|
|
273
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
274
|
+
for (const requestType of ROW_SCOPED_REQUEST_TYPES) {
|
|
275
|
+
await expect(
|
|
276
|
+
TenantPermission.addTenantScopeToQuery(
|
|
277
|
+
modelType,
|
|
278
|
+
{ userId: otherUserId } as any,
|
|
279
|
+
null,
|
|
280
|
+
makeMemberProps(),
|
|
281
|
+
requestType,
|
|
282
|
+
),
|
|
283
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
it.each(NOTIFICATION_CONFIG_MODELS)(
|
|
289
|
+
"leaves a member's own-userId %p filter intact rather than rejecting it",
|
|
290
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
291
|
+
for (const requestType of ROW_SCOPED_REQUEST_TYPES) {
|
|
292
|
+
const query: Query<BaseModel> =
|
|
293
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
294
|
+
modelType,
|
|
295
|
+
{ userId: callerUserId } as any,
|
|
296
|
+
null,
|
|
297
|
+
makeMemberProps(),
|
|
298
|
+
requestType,
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
expect((query as any).userId?.toString()).toBe(callerUserId.toString());
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
it.each(NOTIFICATION_CONFIG_MODELS)(
|
|
307
|
+
"rejects a %p ownership filter disguised as a query operator",
|
|
308
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
309
|
+
/*
|
|
310
|
+
* NotEqual stringifies to the id it wraps, so a string comparison alone
|
|
311
|
+
* would let `userId != me` masquerade as the exact ownership predicate
|
|
312
|
+
* and widen the query to every other row in the project.
|
|
313
|
+
*/
|
|
314
|
+
await expect(
|
|
315
|
+
TenantPermission.addTenantScopeToQuery(
|
|
316
|
+
modelType,
|
|
317
|
+
{ userId: new NotEqual<string>(callerUserId.toString()) } as any,
|
|
318
|
+
null,
|
|
319
|
+
makeMemberProps(),
|
|
320
|
+
DatabaseRequestType.Read,
|
|
321
|
+
),
|
|
322
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
323
|
+
},
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
it.each(NOTIFICATION_CONFIG_MODELS)(
|
|
327
|
+
"refuses a %p query when the caller has no user session at all",
|
|
328
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
329
|
+
/*
|
|
330
|
+
* An API key can carry the auto-granted CurrentUser permission without a
|
|
331
|
+
* userId. There is no id to convert into an ownership predicate, so the
|
|
332
|
+
* request must fail closed rather than run unscoped.
|
|
333
|
+
*/
|
|
334
|
+
await expect(
|
|
335
|
+
TenantPermission.addTenantScopeToQuery(
|
|
336
|
+
modelType,
|
|
337
|
+
{},
|
|
338
|
+
null,
|
|
339
|
+
{
|
|
340
|
+
tenantId: projectId,
|
|
341
|
+
userGlobalAccessPermission: {
|
|
342
|
+
projectIds: [projectId],
|
|
343
|
+
globalPermissions: [Permission.Public, Permission.CurrentUser],
|
|
344
|
+
_type: "UserGlobalAccessPermission",
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
DatabaseRequestType.Read,
|
|
348
|
+
),
|
|
349
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
350
|
+
},
|
|
351
|
+
);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
/*
|
|
355
|
+
* A fan-out query comes back with its predicates already serialized. Each
|
|
356
|
+
* project is re-checked through BasePermission.checkPermissions, which runs
|
|
357
|
+
* QueryUtil.serializeQuery, and that rewrites an ObjectID-valued predicate into
|
|
358
|
+
* QueryHelper.equalTo() - a TypeORM Raw() FindOperator whose uuid does NOT live
|
|
359
|
+
* on `.value` (that slot holds the SQL-generator function) but in
|
|
360
|
+
* `.objectLiteralParameters` under a per-call random key (QueryUtil.ts:222-230,
|
|
361
|
+
* QueryHelper.ts:501-511). The id is therefore the sole VALUE in that bag
|
|
362
|
+
* rather than a value at a known key.
|
|
363
|
+
*/
|
|
364
|
+
function boundIdOf(predicate: unknown): string | undefined {
|
|
365
|
+
const rawOperator:
|
|
366
|
+
| {
|
|
367
|
+
type?: string | undefined;
|
|
368
|
+
objectLiteralParameters?: Record<string, unknown> | undefined;
|
|
369
|
+
}
|
|
370
|
+
| undefined = predicate as
|
|
371
|
+
| {
|
|
372
|
+
type?: string | undefined;
|
|
373
|
+
objectLiteralParameters?: Record<string, unknown> | undefined;
|
|
374
|
+
}
|
|
375
|
+
| undefined;
|
|
376
|
+
|
|
377
|
+
if (!rawOperator || rawOperator.type !== "raw") {
|
|
378
|
+
return undefined;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const boundValues: Array<unknown> = Object.values(
|
|
382
|
+
rawOperator.objectLiteralParameters || {},
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
if (boundValues.length !== 1) {
|
|
386
|
+
return undefined;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return String(boundValues[0]);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
describe("GAP D closed - the rule table opens to a ProjectAdmin on every verb", () => {
|
|
393
|
+
it("lifts the ownership scope on a ProjectAdmin's read, update and delete", async () => {
|
|
394
|
+
/*
|
|
395
|
+
* The inversion of the original GAP D assertion, and the reason the phase
|
|
396
|
+
* exists. Permission.ProjectAdmin now appears in UserNotificationRule's
|
|
397
|
+
* read, update and delete lists, so the intersection between what the admin
|
|
398
|
+
* holds and what the model accepts contains a real role rather than the
|
|
399
|
+
* auto-granted CurrentUser alone. isAccessGrantedOnlyByCurrentUser()
|
|
400
|
+
* returns false, no ownership predicate is stamped on, and the query comes
|
|
401
|
+
* back scoped to the PROJECT rather than to the caller - which is what lets
|
|
402
|
+
* an administrator list every member's rules and notice the member who has
|
|
403
|
+
* none.
|
|
404
|
+
*
|
|
405
|
+
* Delete is in this list on purpose rather than by inheritance. Removing a
|
|
406
|
+
* rule is how an administrator repairs a member whose paging is being
|
|
407
|
+
* swallowed by a stale opt-out row, and it is the only supported way to move
|
|
408
|
+
* a rule between owners now that the ownership column is frozen.
|
|
409
|
+
*/
|
|
410
|
+
for (const requestType of ROW_SCOPED_REQUEST_TYPES) {
|
|
411
|
+
const query: Query<BaseModel> =
|
|
412
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
413
|
+
UserNotificationRule,
|
|
414
|
+
{},
|
|
415
|
+
null,
|
|
416
|
+
makeAdminProps(),
|
|
417
|
+
requestType,
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
expect((query as any).userId).toBeUndefined();
|
|
421
|
+
expect((query as any).projectId?.toString()).toBe(projectId.toString());
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
it("lets a ProjectAdmin name another user on read, update and delete", async () => {
|
|
426
|
+
/*
|
|
427
|
+
* The other half of the same claim, and the half that used to throw. An
|
|
428
|
+
* unscoped query only proves the predicate is no longer stamped on; a query
|
|
429
|
+
* that NAMES the other user proves addCurrentUserScopeToQuery is no longer
|
|
430
|
+
* rejecting the attempt outright, which is what "there is no API by which an
|
|
431
|
+
* admin can read another user's rules" actually meant.
|
|
432
|
+
*/
|
|
433
|
+
for (const requestType of ROW_SCOPED_REQUEST_TYPES) {
|
|
434
|
+
const query: Query<BaseModel> =
|
|
435
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
436
|
+
UserNotificationRule,
|
|
437
|
+
{ userId: otherUserId } as any,
|
|
438
|
+
null,
|
|
439
|
+
makeAdminProps(),
|
|
440
|
+
requestType,
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
expect((query as any).userId?.toString()).toBe(otherUserId.toString());
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it("does not stamp a ProjectAdmin's UserNotificationRule create with their own userId", async () => {
|
|
448
|
+
/*
|
|
449
|
+
* Create widened too, which had to be decided rather than inherited. An
|
|
450
|
+
* administrator provisioning a rule for a member who has none is the single
|
|
451
|
+
* repair that matters most, and it is impossible if the framework stamps the
|
|
452
|
+
* administrator's own id onto the row.
|
|
453
|
+
*
|
|
454
|
+
* The framework deliberately says nothing about WHICH user may be named
|
|
455
|
+
* here - it only stops enforcing "you, and nobody else". The membership
|
|
456
|
+
* question (is this userId even in props.tenantId?) is answered in
|
|
457
|
+
* UserNotificationRuleService, not in this layer, and a passing assertion
|
|
458
|
+
* here must not be read as "on-behalf-of creation is safe".
|
|
459
|
+
*/
|
|
460
|
+
const query: Query<UserNotificationRule> =
|
|
461
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
462
|
+
UserNotificationRule,
|
|
463
|
+
{},
|
|
464
|
+
null,
|
|
465
|
+
makeAdminProps(),
|
|
466
|
+
DatabaseRequestType.Create,
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
expect((query as any).userId).toBeUndefined();
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
it("lifts the scope in the project where the caller is an admin and nowhere else", async () => {
|
|
473
|
+
/*
|
|
474
|
+
* When no single tenantId is supplied the permission layer fans the query
|
|
475
|
+
* out across every project the caller can see and re-checks each one
|
|
476
|
+
* independently. That per-project re-entry is the point: the lift follows
|
|
477
|
+
* the grant, so the project where the caller is merely a member still comes
|
|
478
|
+
* back carrying their own userId while the project where they are a full
|
|
479
|
+
* ProjectAdmin comes back with no ownership predicate at all.
|
|
480
|
+
*
|
|
481
|
+
* Asserted per-project rather than uniformly, because a single loop over
|
|
482
|
+
* both queries is how a fan-out bug that widens the WRONG project would go
|
|
483
|
+
* unnoticed.
|
|
484
|
+
*/
|
|
485
|
+
const memberProjectId: ObjectID = ObjectID.generate();
|
|
486
|
+
const adminProjectId: ObjectID = ObjectID.generate();
|
|
487
|
+
|
|
488
|
+
const queries: Array<Record<string, unknown>> =
|
|
489
|
+
(await TenantPermission.addTenantScopeToQuery(
|
|
490
|
+
UserNotificationRule,
|
|
491
|
+
{},
|
|
492
|
+
null,
|
|
493
|
+
{
|
|
494
|
+
userId: callerUserId,
|
|
495
|
+
userGlobalAccessPermission: {
|
|
496
|
+
projectIds: [memberProjectId, adminProjectId],
|
|
497
|
+
globalPermissions: [Permission.Public, Permission.CurrentUser],
|
|
498
|
+
_type: "UserGlobalAccessPermission",
|
|
499
|
+
},
|
|
500
|
+
userTenantAccessPermission: {
|
|
501
|
+
[adminProjectId.toString()]: {
|
|
502
|
+
projectId: adminProjectId,
|
|
503
|
+
permissions: [
|
|
504
|
+
{
|
|
505
|
+
permission: Permission.ProjectAdmin,
|
|
506
|
+
labelIds: [],
|
|
507
|
+
isBlockPermission: false,
|
|
508
|
+
_type: "UserPermission",
|
|
509
|
+
},
|
|
510
|
+
],
|
|
511
|
+
_type: "UserTenantAccessPermission",
|
|
512
|
+
},
|
|
513
|
+
},
|
|
514
|
+
},
|
|
515
|
+
DatabaseRequestType.Read,
|
|
516
|
+
)) as unknown as Array<Record<string, unknown>>;
|
|
517
|
+
|
|
518
|
+
expect(queries).toHaveLength(2);
|
|
519
|
+
|
|
520
|
+
const queryByProject: Record<string, Record<string, unknown>> = {};
|
|
521
|
+
|
|
522
|
+
for (const query of queries) {
|
|
523
|
+
const boundProjectId: string | undefined = boundIdOf(query["projectId"]);
|
|
524
|
+
|
|
525
|
+
expect(boundProjectId).toBeDefined();
|
|
526
|
+
queryByProject[boundProjectId as string] = query;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const memberProjectQuery: Record<string, unknown> | undefined =
|
|
530
|
+
queryByProject[memberProjectId.toString()];
|
|
531
|
+
const adminProjectQuery: Record<string, unknown> | undefined =
|
|
532
|
+
queryByProject[adminProjectId.toString()];
|
|
533
|
+
|
|
534
|
+
expect(memberProjectQuery).toBeDefined();
|
|
535
|
+
expect(adminProjectQuery).toBeDefined();
|
|
536
|
+
|
|
537
|
+
/*
|
|
538
|
+
* The member project keeps its ownership predicate - and keeps it in the
|
|
539
|
+
* serialized form, which matters beyond shape. TenantPermission
|
|
540
|
+
* .isExactUserScope() accepts only `string | ObjectID`, so a fan-out query
|
|
541
|
+
* fed back into addTenantScopeToQuery would be rejected as a disguised
|
|
542
|
+
* broad filter rather than recognised as the caller's own ownership
|
|
543
|
+
* predicate. The two paths are not round-trippable and no caller may assume
|
|
544
|
+
* they are.
|
|
545
|
+
*/
|
|
546
|
+
expect(memberProjectQuery!["userId"]).toBeDefined();
|
|
547
|
+
expect(memberProjectQuery!["userId"]).not.toBeInstanceOf(ObjectID);
|
|
548
|
+
expect(boundIdOf(memberProjectQuery!["userId"])).toBe(
|
|
549
|
+
callerUserId.toString(),
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
// The admin project carries no ownership predicate in any form.
|
|
553
|
+
expect(adminProjectQuery!["userId"]).toBeUndefined();
|
|
554
|
+
});
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
describe("GAP D closed on the rule table alone - the seven methods open to nobody", () => {
|
|
558
|
+
/*
|
|
559
|
+
* THE BOUNDARY OF THE PHASE, AND THE PART MOST LIKELY TO BE "TIDIED UP"
|
|
560
|
+
* LATER, because seven models that differ from their sibling in all four
|
|
561
|
+
* lists look like an oversight rather than a decision.
|
|
562
|
+
*
|
|
563
|
+
* Two independent reasons keep them closed, and both have to be understood or
|
|
564
|
+
* one of them will be argued away.
|
|
565
|
+
*
|
|
566
|
+
* READ, because the table scope is the only row scope these models have. Each
|
|
567
|
+
* column on them declares `read: [Permission.CurrentUser]`, which is
|
|
568
|
+
* intersected by NAME against a permission set that always contains the
|
|
569
|
+
* auto-granted CurrentUser - so the column lists admit every authenticated
|
|
570
|
+
* caller on their own, and the ownership predicate stamped by this very
|
|
571
|
+
* mechanism is what makes them mean "owner only". Widen the table read and
|
|
572
|
+
* every column on every member's row in the project becomes readable: the
|
|
573
|
+
* webhook URL and its signing secret, the push device token, the Telegram
|
|
574
|
+
* chat id and its verification code. That shipped once and the column-level
|
|
575
|
+
* guard written to contain it did not hold.
|
|
576
|
+
*
|
|
577
|
+
* WRITE, because a rule is a pair - the ownership column decides whose pages
|
|
578
|
+
* select the row, the method relation decides where those pages are
|
|
579
|
+
* delivered. An administrator who could CREATE or EDIT a method on somebody
|
|
580
|
+
* else's account would hold a one-step paging hijack: register a phone or
|
|
581
|
+
* webhook you control on the victim, point their rules at it, and their pages
|
|
582
|
+
* arrive on your device.
|
|
583
|
+
*
|
|
584
|
+
* Neither restriction costs the administrator anything they actually need. A
|
|
585
|
+
* member with no methods must verify a device THEY own, which nobody can do
|
|
586
|
+
* for them, and "does this colleague have a verified method" is answered by
|
|
587
|
+
* OnCallReadinessService's masked payload without this table being read.
|
|
588
|
+
*/
|
|
589
|
+
|
|
590
|
+
it.each(NOTIFICATION_METHOD_MODELS)(
|
|
591
|
+
"still stamps the ownership predicate on a ProjectAdmin's %p READ",
|
|
592
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
593
|
+
/*
|
|
594
|
+
* The inversion of the assertion this group used to open with. The read
|
|
595
|
+
* list is [CurrentUser], so a ProjectAdmin's intersection contains
|
|
596
|
+
* nothing but the auto-granted permission and the predicate is written
|
|
597
|
+
* onto their query exactly as onto a plain member's.
|
|
598
|
+
*
|
|
599
|
+
* This is the shape a leak arrives through rather than the named-target
|
|
600
|
+
* one below: an admin listing page asks for a project's methods rather
|
|
601
|
+
* than one member's, so it issues no userId at all and cannot be refused
|
|
602
|
+
* for naming the wrong one. The stamp is what makes that request
|
|
603
|
+
* harmless.
|
|
604
|
+
*/
|
|
605
|
+
const query: Query<BaseModel> =
|
|
606
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
607
|
+
modelType,
|
|
608
|
+
{},
|
|
609
|
+
null,
|
|
610
|
+
makeAdminProps(),
|
|
611
|
+
DatabaseRequestType.Read,
|
|
612
|
+
);
|
|
613
|
+
|
|
614
|
+
expect((query as any).userId?.toString()).toBe(callerUserId.toString());
|
|
615
|
+
expect((query as any).projectId?.toString()).toBe(projectId.toString());
|
|
616
|
+
},
|
|
617
|
+
);
|
|
618
|
+
|
|
619
|
+
it.each(NOTIFICATION_METHOD_MODELS)(
|
|
620
|
+
"still rejects a ProjectAdmin who names another user's %p rows for read",
|
|
621
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
622
|
+
/*
|
|
623
|
+
* A hard NotAuthorizedException rather than a quiet redirect onto the
|
|
624
|
+
* admin's own rows. The refusal, not the redirect, is what makes "an
|
|
625
|
+
* administrator cannot see a colleague's notification methods" a
|
|
626
|
+
* statement about the API rather than about the UI that happens not to
|
|
627
|
+
* ask.
|
|
628
|
+
*/
|
|
629
|
+
await expect(
|
|
630
|
+
TenantPermission.addTenantScopeToQuery(
|
|
631
|
+
modelType,
|
|
632
|
+
{ userId: otherUserId } as any,
|
|
633
|
+
null,
|
|
634
|
+
makeAdminProps(),
|
|
635
|
+
DatabaseRequestType.Read,
|
|
636
|
+
),
|
|
637
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
638
|
+
},
|
|
639
|
+
);
|
|
640
|
+
|
|
641
|
+
it.each(NOTIFICATION_METHOD_MODELS)(
|
|
642
|
+
"leaves a ProjectAdmin's own-userId %p filter intact on every verb",
|
|
643
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
644
|
+
/*
|
|
645
|
+
* The companion every refusal above needs, and the constraint a
|
|
646
|
+
* heavy-handed fix breaks. An administrator is a member too: they own
|
|
647
|
+
* notification methods, they manage them through these same endpoints,
|
|
648
|
+
* and a change that withheld these rows whenever the caller holds an
|
|
649
|
+
* administrator permission would satisfy every refusal in this group and
|
|
650
|
+
* break the administrator's own settings page.
|
|
651
|
+
*
|
|
652
|
+
* The claim is precisely that ProjectAdmin buys nothing here - not that
|
|
653
|
+
* it costs anything either.
|
|
654
|
+
*/
|
|
655
|
+
for (const requestType of ROW_SCOPED_REQUEST_TYPES) {
|
|
656
|
+
const query: Query<BaseModel> =
|
|
657
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
658
|
+
modelType,
|
|
659
|
+
{ userId: callerUserId } as any,
|
|
660
|
+
null,
|
|
661
|
+
makeAdminProps(),
|
|
662
|
+
requestType,
|
|
663
|
+
);
|
|
664
|
+
|
|
665
|
+
expect((query as any).userId?.toString()).toBe(callerUserId.toString());
|
|
666
|
+
}
|
|
667
|
+
},
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
it.each(NOTIFICATION_METHOD_MODELS)(
|
|
671
|
+
"still forces a ProjectAdmin's %p create, update and delete onto their own rows",
|
|
672
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
673
|
+
/*
|
|
674
|
+
* These three lists were never widened, and this is the assertion that
|
|
675
|
+
* says so. A ProjectAdmin's intersection here contains nothing but the
|
|
676
|
+
* auto-granted permission and they are scoped exactly like the plain
|
|
677
|
+
* member in the first group. An admin permission arriving in any of these
|
|
678
|
+
* three lists breaks this test, which is the entire point of keeping it.
|
|
679
|
+
*/
|
|
680
|
+
for (const requestType of [
|
|
681
|
+
DatabaseRequestType.Create,
|
|
682
|
+
DatabaseRequestType.Update,
|
|
683
|
+
DatabaseRequestType.Delete,
|
|
684
|
+
]) {
|
|
685
|
+
const query: Query<BaseModel> =
|
|
686
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
687
|
+
modelType,
|
|
688
|
+
{},
|
|
689
|
+
null,
|
|
690
|
+
makeAdminProps(),
|
|
691
|
+
requestType,
|
|
692
|
+
);
|
|
693
|
+
|
|
694
|
+
expect((query as any).userId?.toString()).toBe(callerUserId.toString());
|
|
695
|
+
expect((query as any).projectId?.toString()).toBe(projectId.toString());
|
|
696
|
+
}
|
|
697
|
+
},
|
|
698
|
+
);
|
|
699
|
+
|
|
700
|
+
it.each(NOTIFICATION_METHOD_MODELS)(
|
|
701
|
+
"still rejects a ProjectAdmin who explicitly targets another user's %p rows for write",
|
|
702
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
703
|
+
/*
|
|
704
|
+
* A hard NotAuthorizedException rather than a quiet redirect, and here the
|
|
705
|
+
* difference is load-bearing beyond legibility: service hooks run before
|
|
706
|
+
* the final permission check, so silently rewriting the target would let a
|
|
707
|
+
* hook inspect one row while the database operation mutated a different
|
|
708
|
+
* one.
|
|
709
|
+
*/
|
|
710
|
+
for (const requestType of [
|
|
711
|
+
DatabaseRequestType.Update,
|
|
712
|
+
DatabaseRequestType.Delete,
|
|
713
|
+
]) {
|
|
714
|
+
await expect(
|
|
715
|
+
TenantPermission.addTenantScopeToQuery(
|
|
716
|
+
modelType,
|
|
717
|
+
{ userId: otherUserId } as any,
|
|
718
|
+
null,
|
|
719
|
+
makeAdminProps(),
|
|
720
|
+
requestType,
|
|
721
|
+
),
|
|
722
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
);
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
describe("TeamMember proves the mechanism - a listed admin permission lifts the scope", () => {
|
|
729
|
+
it("does not scope a ProjectAdmin's TeamMember read to their own userId", async () => {
|
|
730
|
+
/*
|
|
731
|
+
* TeamMember carries the identical @CurrentUserCanAccessRecordBy("userId")
|
|
732
|
+
* decorator as the notification models, and yet the admin walks away
|
|
733
|
+
* unscoped. The difference is one entry: ProjectAdmin appears in
|
|
734
|
+
* TeamMember's read list, so the intersection contains a real role and
|
|
735
|
+
* isAccessGrantedOnlyByCurrentUser() returns false.
|
|
736
|
+
*
|
|
737
|
+
* That is the whole of what the rule table gained, on a model that has
|
|
738
|
+
* always shipped it - which is why the fix there was an entry in a list
|
|
739
|
+
* rather than a new gate, and equally why the seven method models stay
|
|
740
|
+
* closed by simply having no such entry. Nothing guards them beyond the
|
|
741
|
+
* absence, so this group stays here as the independent statement of what
|
|
742
|
+
* the absence is doing.
|
|
743
|
+
*/
|
|
744
|
+
const query: Query<TeamMember> =
|
|
745
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
746
|
+
TeamMember,
|
|
747
|
+
{},
|
|
748
|
+
null,
|
|
749
|
+
makeAdminProps(),
|
|
750
|
+
DatabaseRequestType.Read,
|
|
751
|
+
);
|
|
752
|
+
|
|
753
|
+
expect((query as any).userId).toBeUndefined();
|
|
754
|
+
expect((query as any).projectId?.toString()).toBe(projectId.toString());
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
it("scopes a plain member's TeamMember read to their own userId", async () => {
|
|
758
|
+
const query: Query<TeamMember> =
|
|
759
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
760
|
+
TeamMember,
|
|
761
|
+
{},
|
|
762
|
+
null,
|
|
763
|
+
makeMemberProps(),
|
|
764
|
+
DatabaseRequestType.Read,
|
|
765
|
+
);
|
|
766
|
+
|
|
767
|
+
expect((query as any).userId?.toString()).toBe(callerUserId.toString());
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
it("lets a ProjectAdmin read another user's TeamMember rows without throwing", async () => {
|
|
771
|
+
const query: Query<TeamMember> =
|
|
772
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
773
|
+
TeamMember,
|
|
774
|
+
{ userId: otherUserId } as any,
|
|
775
|
+
null,
|
|
776
|
+
makeAdminProps(),
|
|
777
|
+
DatabaseRequestType.Read,
|
|
778
|
+
);
|
|
779
|
+
|
|
780
|
+
expect((query as any).userId?.toString()).toBe(otherUserId.toString());
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
it("rejects a plain member reading another user's TeamMember rows", async () => {
|
|
784
|
+
await expect(
|
|
785
|
+
TenantPermission.addTenantScopeToQuery(
|
|
786
|
+
TeamMember,
|
|
787
|
+
{ userId: otherUserId } as any,
|
|
788
|
+
null,
|
|
789
|
+
makeMemberProps(),
|
|
790
|
+
DatabaseRequestType.Read,
|
|
791
|
+
),
|
|
792
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
it("still scopes a ProjectAdmin's TeamMember UPDATE, because ProjectAdmin is not in the update list", async () => {
|
|
796
|
+
/*
|
|
797
|
+
* The exemption is granted per-operation, not per-model, and TeamMember
|
|
798
|
+
* demonstrates it on a shipping model. That is what makes the rule table's
|
|
799
|
+
* asymmetry expressible at all - read widened for one set of permissions,
|
|
800
|
+
* write for another - and what would let a future method model be opened on
|
|
801
|
+
* one verb without being opened on the rest, should anyone ever find a
|
|
802
|
+
* verb that is safe to open.
|
|
803
|
+
*
|
|
804
|
+
* TeamMember's update list is
|
|
805
|
+
* [ProjectOwner, InviteProjectTeamMembers, EditProjectTeam, CurrentUser] -
|
|
806
|
+
* ProjectAdmin is absent - so a caller holding ONLY ProjectAdmin is
|
|
807
|
+
* force-scoped on update even though they were unscoped on read.
|
|
808
|
+
*/
|
|
809
|
+
const query: Query<TeamMember> =
|
|
810
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
811
|
+
TeamMember,
|
|
812
|
+
{},
|
|
813
|
+
null,
|
|
814
|
+
makeAdminProps(),
|
|
815
|
+
DatabaseRequestType.Update,
|
|
816
|
+
);
|
|
817
|
+
|
|
818
|
+
expect((query as any).userId?.toString()).toBe(callerUserId.toString());
|
|
819
|
+
});
|
|
820
|
+
|
|
821
|
+
it("does not row-scope a TeamMember delete at all, because CurrentUser is not in the delete list", async () => {
|
|
822
|
+
/*
|
|
823
|
+
* TeamMember's delete list omits CurrentUser entirely, so
|
|
824
|
+
* isAccessGrantedOnlyByCurrentUser() short-circuits to false before any
|
|
825
|
+
* ownership predicate is considered. Nothing is added to the query here -
|
|
826
|
+
* it is the separate table-level permission check that stops a plain
|
|
827
|
+
* member from deleting memberships.
|
|
828
|
+
*/
|
|
829
|
+
const query: Query<TeamMember> =
|
|
830
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
831
|
+
TeamMember,
|
|
832
|
+
{},
|
|
833
|
+
null,
|
|
834
|
+
makeMemberProps(),
|
|
835
|
+
DatabaseRequestType.Delete,
|
|
836
|
+
);
|
|
837
|
+
|
|
838
|
+
expect((query as any).userId).toBeUndefined();
|
|
839
|
+
expect((query as any).projectId?.toString()).toBe(projectId.toString());
|
|
840
|
+
});
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
describe("the lift mechanism in isolation, on a throwaway model", () => {
|
|
844
|
+
/*
|
|
845
|
+
* The production groups above assert what UserNotificationRule and the seven
|
|
846
|
+
* methods DO; this group asserts what the framework does with any user-scoped
|
|
847
|
+
* model, on a class whose lists match neither of them - all four widened on
|
|
848
|
+
* the rule table, all four closed on the methods, two-of-four here.
|
|
849
|
+
*
|
|
850
|
+
* That mismatch is the point. If a future change to TenantPermission alters
|
|
851
|
+
* the rule, this group fails on its own terms and says so, instead of the
|
|
852
|
+
* failure arriving disguised as eight models having drifted.
|
|
853
|
+
*/
|
|
854
|
+
|
|
855
|
+
it("lifts the ownership scope for a ProjectAdmin on read and update", async () => {
|
|
856
|
+
for (const requestType of [
|
|
857
|
+
DatabaseRequestType.Read,
|
|
858
|
+
DatabaseRequestType.Update,
|
|
859
|
+
]) {
|
|
860
|
+
const query: Query<BaseModel> =
|
|
861
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
862
|
+
AdminReadableNotificationRuleModel,
|
|
863
|
+
{},
|
|
864
|
+
null,
|
|
865
|
+
makeAdminProps(),
|
|
866
|
+
requestType,
|
|
867
|
+
);
|
|
868
|
+
|
|
869
|
+
expect((query as any).userId).toBeUndefined();
|
|
870
|
+
expect((query as any).projectId?.toString()).toBe(projectId.toString());
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
it("lets a ProjectAdmin target another user's rows once the permission is listed", async () => {
|
|
875
|
+
const query: Query<BaseModel> =
|
|
876
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
877
|
+
AdminReadableNotificationRuleModel,
|
|
878
|
+
{ userId: otherUserId } as any,
|
|
879
|
+
null,
|
|
880
|
+
makeAdminProps(),
|
|
881
|
+
DatabaseRequestType.Read,
|
|
882
|
+
);
|
|
883
|
+
|
|
884
|
+
expect((query as any).userId?.toString()).toBe(otherUserId.toString());
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
it("keeps the ownership scope on a plain member for read, update and delete", async () => {
|
|
888
|
+
for (const requestType of ROW_SCOPED_REQUEST_TYPES) {
|
|
889
|
+
const query: Query<BaseModel> =
|
|
890
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
891
|
+
AdminReadableNotificationRuleModel,
|
|
892
|
+
{},
|
|
893
|
+
null,
|
|
894
|
+
makeMemberProps(),
|
|
895
|
+
requestType,
|
|
896
|
+
);
|
|
897
|
+
|
|
898
|
+
expect((query as any).userId?.toString()).toBe(callerUserId.toString());
|
|
899
|
+
}
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
it("still rejects a plain member targeting another user once admins are exempt", async () => {
|
|
903
|
+
await expect(
|
|
904
|
+
TenantPermission.addTenantScopeToQuery(
|
|
905
|
+
AdminReadableNotificationRuleModel,
|
|
906
|
+
{ userId: otherUserId } as any,
|
|
907
|
+
null,
|
|
908
|
+
makeMemberProps(),
|
|
909
|
+
DatabaseRequestType.Read,
|
|
910
|
+
),
|
|
911
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
it("keeps the delete scope on a ProjectAdmin, since delete was left CurrentUser-only", async () => {
|
|
915
|
+
/*
|
|
916
|
+
* The exemption is granted per-operation: adding ProjectAdmin to read and
|
|
917
|
+
* update alone leaves delete untouched. Proved here on a class whose lists
|
|
918
|
+
* nothing else depends on, so the guarantee survives any future edit to a
|
|
919
|
+
* production model - including the edit that would widen a notification
|
|
920
|
+
* method on one verb while believing the rest stay closed.
|
|
921
|
+
*/
|
|
922
|
+
const query: Query<BaseModel> =
|
|
923
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
924
|
+
AdminReadableNotificationRuleModel,
|
|
925
|
+
{},
|
|
926
|
+
null,
|
|
927
|
+
makeAdminProps(),
|
|
928
|
+
DatabaseRequestType.Delete,
|
|
929
|
+
);
|
|
930
|
+
|
|
931
|
+
expect((query as any).userId?.toString()).toBe(callerUserId.toString());
|
|
932
|
+
});
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
describe("notification config model decorators", () => {
|
|
936
|
+
it.each(NOTIFICATION_CONFIG_MODELS)(
|
|
937
|
+
"declares userId as %p's ownership column and projectId as its tenant column",
|
|
938
|
+
(modelType: ModelTypeUnderTest): void => {
|
|
939
|
+
const model: BaseModel = new modelType();
|
|
940
|
+
|
|
941
|
+
expect(model.getUserColumn()).toBe("userId");
|
|
942
|
+
expect(model.getTenantColumn()).toBe("projectId");
|
|
943
|
+
},
|
|
944
|
+
);
|
|
945
|
+
|
|
946
|
+
it("grants UserNotificationRule table access to CurrentUser plus the administrator grants, on all four verbs", () => {
|
|
947
|
+
/*
|
|
948
|
+
* Pinned literally rather than with `toContain`, and the direction matters:
|
|
949
|
+
* the failure mode worth catching on a widened list is an entry ARRIVING,
|
|
950
|
+
* not one going missing, and a containment check passes straight through the
|
|
951
|
+
* change it exists to catch.
|
|
952
|
+
*
|
|
953
|
+
* CurrentUser stays FIRST and stays present in every list. It is what keeps
|
|
954
|
+
* a plain member scoped to their own rows; drop it and the first group in
|
|
955
|
+
* this file - the one that proves members are still confined - stops being
|
|
956
|
+
* about anything.
|
|
957
|
+
*/
|
|
958
|
+
const model: UserNotificationRule = new UserNotificationRule();
|
|
959
|
+
|
|
960
|
+
expect(model.getReadPermissions()).toEqual([
|
|
961
|
+
Permission.CurrentUser,
|
|
962
|
+
...ADMIN_READ_GRANTS,
|
|
963
|
+
]);
|
|
964
|
+
expect(model.getCreatePermissions()).toEqual([
|
|
965
|
+
Permission.CurrentUser,
|
|
966
|
+
...ADMIN_WRITE_GRANTS,
|
|
967
|
+
]);
|
|
968
|
+
expect(model.getUpdatePermissions()).toEqual([
|
|
969
|
+
Permission.CurrentUser,
|
|
970
|
+
...ADMIN_WRITE_GRANTS,
|
|
971
|
+
]);
|
|
972
|
+
expect(model.getDeletePermissions()).toEqual([
|
|
973
|
+
Permission.CurrentUser,
|
|
974
|
+
...ADMIN_WRITE_GRANTS,
|
|
975
|
+
]);
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
it.each(NOTIFICATION_METHOD_MODELS)(
|
|
979
|
+
"keeps all four of %p's table lists CurrentUser-only",
|
|
980
|
+
(modelType: ModelTypeUnderTest): void => {
|
|
981
|
+
/*
|
|
982
|
+
* The decorator-level statement of what the behavioural group above
|
|
983
|
+
* asserts. Both are needed: the behaviour is what actually protects a
|
|
984
|
+
* member, but a list can be widened by a refactor months before anybody
|
|
985
|
+
* writes a query that notices, and this fails on the commit that does it.
|
|
986
|
+
*
|
|
987
|
+
* READ IS THE ENTRY TO WATCH. It is the one that shipped widened and was
|
|
988
|
+
* reverted, so it is the one a later commit is most likely to re-add
|
|
989
|
+
* while "restoring the admin feature" - and re-adding it silently removes
|
|
990
|
+
* the row scope that every column on the model depends on. Neither
|
|
991
|
+
* ADMIN_READ_GRANTS nor ADMIN_WRITE_GRANTS belongs in any list on these
|
|
992
|
+
* seven; there is no verb on a notification method that an administrator
|
|
993
|
+
* may perform on somebody else's row.
|
|
994
|
+
*/
|
|
995
|
+
const model: BaseModel = new modelType();
|
|
996
|
+
|
|
997
|
+
for (const list of [
|
|
998
|
+
model.getReadPermissions(),
|
|
999
|
+
model.getCreatePermissions(),
|
|
1000
|
+
model.getUpdatePermissions(),
|
|
1001
|
+
model.getDeletePermissions(),
|
|
1002
|
+
]) {
|
|
1003
|
+
expect(list).toEqual([Permission.CurrentUser]);
|
|
1004
|
+
}
|
|
1005
|
+
},
|
|
1006
|
+
);
|
|
1007
|
+
|
|
1008
|
+
it.each(NOTIFICATION_CONFIG_MODELS)(
|
|
1009
|
+
"does not let %p be queried across tenants",
|
|
1010
|
+
(modelType: ModelTypeUnderTest): void => {
|
|
1011
|
+
/*
|
|
1012
|
+
* canQueryMultiTenant() is what would let a caller ask for rows without
|
|
1013
|
+
* naming a project. These models say no, so the fan-out path is the only
|
|
1014
|
+
* multi-project route and it re-checks permissions per project.
|
|
1015
|
+
*/
|
|
1016
|
+
const model: BaseModel = new modelType();
|
|
1017
|
+
|
|
1018
|
+
expect(model.canQueryMultiTenant()).toBe(false);
|
|
1019
|
+
},
|
|
1020
|
+
);
|
|
1021
|
+
|
|
1022
|
+
it("keeps the UserNotificationRule ownership column unwritable after creation", () => {
|
|
1023
|
+
const model: UserNotificationRule = new UserNotificationRule();
|
|
1024
|
+
|
|
1025
|
+
expect(model.getColumnAccessControlFor("userId")?.update).toEqual([]);
|
|
1026
|
+
expect(model.getColumnAccessControlFor("user")?.update).toEqual([]);
|
|
1027
|
+
expect(model.getColumnAccessControlFor("projectId")?.update).toEqual([]);
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
it("names no administrator permission on the webhook URL's read list", () => {
|
|
1031
|
+
/*
|
|
1032
|
+
* A webhook URL frequently carries its own bearer token in the path or
|
|
1033
|
+
* query string, so it is the most sensitive column in this group and no
|
|
1034
|
+
* admin permission may ever appear on its read list.
|
|
1035
|
+
*
|
|
1036
|
+
* NECESSARY, NOT SUFFICIENT - and the gap between the two is the trap the
|
|
1037
|
+
* reverted widening walked into. `read: [CurrentUser]` does not mean
|
|
1038
|
+
* "readable only on my own row": Permission.CurrentUser is auto-granted to
|
|
1039
|
+
* every authenticated caller and ColumnPermissions intersects by NAME
|
|
1040
|
+
* without ever seeing the query, so this list alone says nothing more than
|
|
1041
|
+
* "readable by anyone logged in". It is equivalent to owner-only only
|
|
1042
|
+
* because the TABLE list pins the row scope to the caller - which is why the
|
|
1043
|
+
* table assertions above are the ones doing the work, and why this one only
|
|
1044
|
+
* catches the cruder mistake of pasting the admin grants in here too.
|
|
1045
|
+
*/
|
|
1046
|
+
const model: UserWebhook = new UserWebhook();
|
|
1047
|
+
|
|
1048
|
+
expect(model.getColumnAccessControlFor("webhookUrl")?.read).toEqual([
|
|
1049
|
+
Permission.CurrentUser,
|
|
1050
|
+
]);
|
|
1051
|
+
|
|
1052
|
+
for (const grant of [...ADMIN_READ_GRANTS, ...ADMIN_WRITE_GRANTS]) {
|
|
1053
|
+
expect(model.getColumnAccessControlFor("webhookUrl")?.read).not.toContain(
|
|
1054
|
+
grant,
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
expect(model.getColumnAccessControlFor("webhookUrl")?.read).not.toContain(
|
|
1059
|
+
Permission.ProjectMember,
|
|
1060
|
+
);
|
|
1061
|
+
});
|
|
1062
|
+
|
|
1063
|
+
it("keeps UserWebhook's ownership column CurrentUser-only on read and unwritable on update", () => {
|
|
1064
|
+
/*
|
|
1065
|
+
* Widened on the read side once and reverted, so both halves are pinned
|
|
1066
|
+
* here for different reasons.
|
|
1067
|
+
*
|
|
1068
|
+
* READ went back to CurrentUser because there is no longer any question an
|
|
1069
|
+
* administrator can ask of this table. "Whose row is this" is only worth
|
|
1070
|
+
* answering to a caller who can reach somebody else's row, and none can;
|
|
1071
|
+
* leaving the ownership column widened would be a standing invitation to
|
|
1072
|
+
* re-widen the table so that the column meant something again.
|
|
1073
|
+
*
|
|
1074
|
+
* UPDATE stays empty for everybody, which is the more important half and was
|
|
1075
|
+
* never in question. A writable ownership column would let an administrator
|
|
1076
|
+
* RE-POINT an existing row at a different owner: take a webhook that already
|
|
1077
|
+
* points at an endpoint you control, move its userId to a colleague, and
|
|
1078
|
+
* their pages arrive at your endpoint. That is the create-side ownership
|
|
1079
|
+
* gate reopened through a different verb, and nothing at the row level
|
|
1080
|
+
* distinguishes it from a legitimate edit.
|
|
1081
|
+
*/
|
|
1082
|
+
const model: UserWebhook = new UserWebhook();
|
|
1083
|
+
|
|
1084
|
+
expect(model.getColumnAccessControlFor("userId")?.read).toEqual([
|
|
1085
|
+
Permission.CurrentUser,
|
|
1086
|
+
]);
|
|
1087
|
+
expect(model.getColumnAccessControlFor("userId")?.update).toEqual([]);
|
|
1088
|
+
});
|
|
1089
|
+
});
|