@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,1219 @@
|
|
|
1
|
+
import UserCall from "../../../../../Models/DatabaseModels/UserCall";
|
|
2
|
+
import UserEmail from "../../../../../Models/DatabaseModels/UserEmail";
|
|
3
|
+
import UserPush from "../../../../../Models/DatabaseModels/UserPush";
|
|
4
|
+
import UserSMS from "../../../../../Models/DatabaseModels/UserSMS";
|
|
5
|
+
import UserTelegram from "../../../../../Models/DatabaseModels/UserTelegram";
|
|
6
|
+
import UserWebhook from "../../../../../Models/DatabaseModels/UserWebhook";
|
|
7
|
+
import UserWhatsApp from "../../../../../Models/DatabaseModels/UserWhatsApp";
|
|
8
|
+
import BaseModel from "../../../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
9
|
+
import DatabaseService from "../../../../../Server/Services/DatabaseService";
|
|
10
|
+
import FindBy from "../../../../../Server/Types/Database/FindBy";
|
|
11
|
+
import ModelPermission from "../../../../../Server/Types/Database/Permissions/Index";
|
|
12
|
+
import { CheckReadPermissionType } from "../../../../../Server/Types/Database/Permissions/ReadPermission";
|
|
13
|
+
import Query from "../../../../../Server/Types/Database/Query";
|
|
14
|
+
import Select from "../../../../../Server/Types/Database/Select";
|
|
15
|
+
import NotEqual from "../../../../../Types/BaseDatabase/NotEqual";
|
|
16
|
+
import SortOrder from "../../../../../Types/BaseDatabase/SortOrder";
|
|
17
|
+
import DatabaseCommonInteractionProps from "../../../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
18
|
+
import ColumnAccessControl from "../../../../../Types/Database/AccessControl/ColumnAccessControl";
|
|
19
|
+
import TableAccessControl from "../../../../../Types/Database/AccessControl/TableAccessControl";
|
|
20
|
+
import CurrentUserCanAccessRecordBy from "../../../../../Types/Database/CurrentUserCanAccessRecordBy";
|
|
21
|
+
import TableColumn from "../../../../../Types/Database/TableColumn";
|
|
22
|
+
import TableColumnType from "../../../../../Types/Database/TableColumnType";
|
|
23
|
+
import TenantColumn from "../../../../../Types/Database/TenantColumn";
|
|
24
|
+
import NotAuthorizedException from "../../../../../Types/Exception/NotAuthorizedException";
|
|
25
|
+
import ObjectID from "../../../../../Types/ObjectID";
|
|
26
|
+
import Permission from "../../../../../Types/Permission";
|
|
27
|
+
import UserType from "../../../../../Types/UserType";
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* WHAT THIS FILE PINS
|
|
31
|
+
*
|
|
32
|
+
* @OwnerOnlyColumn() marks a column that may be read only by a query pinned to
|
|
33
|
+
* the row's owner. Phase 3 widens UserNotificationRule's TABLE read to
|
|
34
|
+
* administrators - which is the feature, and is correct - and the moment it
|
|
35
|
+
* does, an admin's read of that table is no longer confined to their own rows.
|
|
36
|
+
* Everything reachable from those rows is then reachable by an admin, and the
|
|
37
|
+
* seven notification-method models hang off them by ManyToOne relation.
|
|
38
|
+
*
|
|
39
|
+
* There are FOUR routes into a marked column, and closing three of them is the
|
|
40
|
+
* same as closing none. Every route below is driven through the real permission
|
|
41
|
+
* entry point - ModelPermission.checkReadQueryPermission for the query and
|
|
42
|
+
* select routes, DatabaseService's own sort-injection for the sort route -
|
|
43
|
+
* never by asserting on decorator metadata. A guard that is only proved by
|
|
44
|
+
* reading back the mark that configures it proves nothing about whether the
|
|
45
|
+
* mark is consulted.
|
|
46
|
+
*
|
|
47
|
+
* Route 1 select: { webhookUrl: true } on UserWebhook
|
|
48
|
+
* Route 2 select: { userWebhook: { webhookUrl: true } } on a rule
|
|
49
|
+
* Route 3 sort: { webhookUrl: "ASC" } injected post-gate
|
|
50
|
+
* Route 4 query: { webhookUrl: "https://..." } as a value oracle
|
|
51
|
+
*
|
|
52
|
+
* HOW THE ADMIN CASE IS SET UP, AND WHY IT IS NOT THEATRE. Today the seven
|
|
53
|
+
* method models list [CurrentUser] and nothing else, so TenantPermission stamps
|
|
54
|
+
* every non-root caller's own userId onto their query and an administrator is
|
|
55
|
+
* indistinguishable from a plain member - the admin case is currently
|
|
56
|
+
* unreachable on those models, and that is precisely what Phase 3 changes. The
|
|
57
|
+
* AdminReadable* classes below are the REAL models with the REAL marked columns
|
|
58
|
+
* and one thing altered: Permission.ProjectAdmin added to the table read list,
|
|
59
|
+
* exactly the change Phase 3 makes. Nothing about the columns, the ownership
|
|
60
|
+
* column or the relation metadata is simulated.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
const projectId: ObjectID = ObjectID.generate();
|
|
64
|
+
const ownerUserId: ObjectID = ObjectID.generate();
|
|
65
|
+
const adminUserId: ObjectID = ObjectID.generate();
|
|
66
|
+
const otherUserId: ObjectID = ObjectID.generate();
|
|
67
|
+
|
|
68
|
+
type ModelTypeUnderTest = { new (): BaseModel };
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
* The seven notification-method models with the post-Phase-3 table read. Only
|
|
72
|
+
* the table access control is restated; every column, its @OwnerOnlyColumn
|
|
73
|
+
* mark, the tenant column and @CurrentUserCanAccessRecordBy("userId") are
|
|
74
|
+
* inherited from the production model.
|
|
75
|
+
*/
|
|
76
|
+
const ADMIN_READABLE_TABLE_ACCESS: {
|
|
77
|
+
create: Array<Permission>;
|
|
78
|
+
read: Array<Permission>;
|
|
79
|
+
update: Array<Permission>;
|
|
80
|
+
delete: Array<Permission>;
|
|
81
|
+
} = {
|
|
82
|
+
create: [Permission.CurrentUser],
|
|
83
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
84
|
+
update: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
85
|
+
delete: [Permission.CurrentUser],
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
@TableAccessControl(ADMIN_READABLE_TABLE_ACCESS)
|
|
89
|
+
class AdminReadableUserEmail extends UserEmail {}
|
|
90
|
+
|
|
91
|
+
@TableAccessControl(ADMIN_READABLE_TABLE_ACCESS)
|
|
92
|
+
class AdminReadableUserSMS extends UserSMS {}
|
|
93
|
+
|
|
94
|
+
@TableAccessControl(ADMIN_READABLE_TABLE_ACCESS)
|
|
95
|
+
class AdminReadableUserCall extends UserCall {}
|
|
96
|
+
|
|
97
|
+
@TableAccessControl(ADMIN_READABLE_TABLE_ACCESS)
|
|
98
|
+
class AdminReadableUserPush extends UserPush {}
|
|
99
|
+
|
|
100
|
+
@TableAccessControl(ADMIN_READABLE_TABLE_ACCESS)
|
|
101
|
+
class AdminReadableUserWhatsApp extends UserWhatsApp {}
|
|
102
|
+
|
|
103
|
+
@TableAccessControl(ADMIN_READABLE_TABLE_ACCESS)
|
|
104
|
+
class AdminReadableUserTelegram extends UserTelegram {}
|
|
105
|
+
|
|
106
|
+
@TableAccessControl(ADMIN_READABLE_TABLE_ACCESS)
|
|
107
|
+
class AdminReadableUserWebhook extends UserWebhook {}
|
|
108
|
+
|
|
109
|
+
/*
|
|
110
|
+
* UserNotificationRule's shape after Phase 3: readable by an administrator,
|
|
111
|
+
* still owned by a user, and pointing at the REAL method models through the
|
|
112
|
+
* same ManyToOne relations the production rule model uses. The relation columns
|
|
113
|
+
* carry read permissions an admin holds, because the point of Phase 3 is that
|
|
114
|
+
* an admin CAN read this table - the question this file answers is what they
|
|
115
|
+
* can reach through it.
|
|
116
|
+
*/
|
|
117
|
+
@TenantColumn("projectId")
|
|
118
|
+
@TableAccessControl(ADMIN_READABLE_TABLE_ACCESS)
|
|
119
|
+
@CurrentUserCanAccessRecordBy("userId")
|
|
120
|
+
class AdminReadableRuleModel extends BaseModel {
|
|
121
|
+
@ColumnAccessControl({
|
|
122
|
+
create: [Permission.CurrentUser],
|
|
123
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
124
|
+
update: [],
|
|
125
|
+
})
|
|
126
|
+
@TableColumn({
|
|
127
|
+
type: TableColumnType.ObjectID,
|
|
128
|
+
title: "Project ID",
|
|
129
|
+
})
|
|
130
|
+
public projectId?: ObjectID = undefined;
|
|
131
|
+
|
|
132
|
+
@ColumnAccessControl({
|
|
133
|
+
create: [Permission.CurrentUser],
|
|
134
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
135
|
+
update: [],
|
|
136
|
+
})
|
|
137
|
+
@TableColumn({
|
|
138
|
+
type: TableColumnType.ObjectID,
|
|
139
|
+
title: "User ID",
|
|
140
|
+
})
|
|
141
|
+
public userId?: ObjectID = undefined;
|
|
142
|
+
|
|
143
|
+
@ColumnAccessControl({
|
|
144
|
+
create: [Permission.CurrentUser],
|
|
145
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
146
|
+
update: [],
|
|
147
|
+
})
|
|
148
|
+
@TableColumn({
|
|
149
|
+
type: TableColumnType.Entity,
|
|
150
|
+
modelType: UserEmail,
|
|
151
|
+
manyToOneRelationColumn: "userEmailId",
|
|
152
|
+
title: "User Email",
|
|
153
|
+
})
|
|
154
|
+
public userEmail?: UserEmail = undefined;
|
|
155
|
+
|
|
156
|
+
@ColumnAccessControl({
|
|
157
|
+
create: [Permission.CurrentUser],
|
|
158
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
159
|
+
update: [],
|
|
160
|
+
})
|
|
161
|
+
@TableColumn({
|
|
162
|
+
type: TableColumnType.Entity,
|
|
163
|
+
modelType: UserSMS,
|
|
164
|
+
manyToOneRelationColumn: "userSmsId",
|
|
165
|
+
title: "User SMS",
|
|
166
|
+
})
|
|
167
|
+
public userSms?: UserSMS = undefined;
|
|
168
|
+
|
|
169
|
+
@ColumnAccessControl({
|
|
170
|
+
create: [Permission.CurrentUser],
|
|
171
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
172
|
+
update: [],
|
|
173
|
+
})
|
|
174
|
+
@TableColumn({
|
|
175
|
+
type: TableColumnType.Entity,
|
|
176
|
+
modelType: UserCall,
|
|
177
|
+
manyToOneRelationColumn: "userCallId",
|
|
178
|
+
title: "User Call",
|
|
179
|
+
})
|
|
180
|
+
public userCall?: UserCall = undefined;
|
|
181
|
+
|
|
182
|
+
@ColumnAccessControl({
|
|
183
|
+
create: [Permission.CurrentUser],
|
|
184
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
185
|
+
update: [],
|
|
186
|
+
})
|
|
187
|
+
@TableColumn({
|
|
188
|
+
type: TableColumnType.Entity,
|
|
189
|
+
modelType: UserPush,
|
|
190
|
+
manyToOneRelationColumn: "userPushId",
|
|
191
|
+
title: "User Push",
|
|
192
|
+
})
|
|
193
|
+
public userPush?: UserPush = undefined;
|
|
194
|
+
|
|
195
|
+
@ColumnAccessControl({
|
|
196
|
+
create: [Permission.CurrentUser],
|
|
197
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
198
|
+
update: [],
|
|
199
|
+
})
|
|
200
|
+
@TableColumn({
|
|
201
|
+
type: TableColumnType.Entity,
|
|
202
|
+
modelType: UserWhatsApp,
|
|
203
|
+
manyToOneRelationColumn: "userWhatsAppId",
|
|
204
|
+
title: "User WhatsApp",
|
|
205
|
+
})
|
|
206
|
+
public userWhatsApp?: UserWhatsApp = undefined;
|
|
207
|
+
|
|
208
|
+
@ColumnAccessControl({
|
|
209
|
+
create: [Permission.CurrentUser],
|
|
210
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
211
|
+
update: [],
|
|
212
|
+
})
|
|
213
|
+
@TableColumn({
|
|
214
|
+
type: TableColumnType.Entity,
|
|
215
|
+
modelType: UserTelegram,
|
|
216
|
+
manyToOneRelationColumn: "userTelegramId",
|
|
217
|
+
title: "User Telegram",
|
|
218
|
+
})
|
|
219
|
+
public userTelegram?: UserTelegram = undefined;
|
|
220
|
+
|
|
221
|
+
@ColumnAccessControl({
|
|
222
|
+
create: [Permission.CurrentUser],
|
|
223
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
224
|
+
update: [],
|
|
225
|
+
})
|
|
226
|
+
@TableColumn({
|
|
227
|
+
type: TableColumnType.Entity,
|
|
228
|
+
modelType: UserWebhook,
|
|
229
|
+
manyToOneRelationColumn: "userWebhookId",
|
|
230
|
+
title: "User Webhook",
|
|
231
|
+
})
|
|
232
|
+
public userWebhook?: UserWebhook = undefined;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
interface MethodModelUnderTest {
|
|
236
|
+
name: string;
|
|
237
|
+
/* The production model, whose table read is [CurrentUser] today. */
|
|
238
|
+
modelType: ModelTypeUnderTest;
|
|
239
|
+
/* The same model with Phase 3's widened table read. */
|
|
240
|
+
adminReadableModelType: ModelTypeUnderTest;
|
|
241
|
+
/* The relation this method hangs off on a notification rule. */
|
|
242
|
+
relationColumnName: string;
|
|
243
|
+
/* Every column marked @OwnerOnlyColumn() on the model. */
|
|
244
|
+
ownerOnlyColumns: Array<string>;
|
|
245
|
+
/*
|
|
246
|
+
* The marked columns this guard actually decides: marked AND selectable by an
|
|
247
|
+
* ordinary authenticated caller.
|
|
248
|
+
*
|
|
249
|
+
* The four SMS/call/email/WhatsApp verification codes are marked but carry
|
|
250
|
+
* `read: []`, so the column-permission layer already refuses them to
|
|
251
|
+
* everybody including their owner - asserting on those would test the older
|
|
252
|
+
* gate, not this one. UserTelegram.verificationCode is the instructive
|
|
253
|
+
* counter-example: it is readable by CurrentUser (the user has to be shown
|
|
254
|
+
* the code to type into the bot), and CurrentUser is auto-granted to every
|
|
255
|
+
* authenticated caller, so the owner-only mark is the ONLY thing standing
|
|
256
|
+
* between it and any admin in the project.
|
|
257
|
+
*/
|
|
258
|
+
ownerOnlyColumnsSelectableByOwner: Array<string>;
|
|
259
|
+
/*
|
|
260
|
+
* A marked column that is ALSO canReadOnRelationQuery, i.e. one that a nested
|
|
261
|
+
* select can actually ask for. This is the route-2 attack surface.
|
|
262
|
+
*/
|
|
263
|
+
ownerOnlyColumnReachableThroughRelation: string;
|
|
264
|
+
/*
|
|
265
|
+
* An unmarked column that a nested select can ask for. This is what an admin
|
|
266
|
+
* surface labels rows with, and it must keep working.
|
|
267
|
+
*/
|
|
268
|
+
labelColumnReachableThroughRelation: string;
|
|
269
|
+
/* Unmarked columns an admin must keep being able to read directly. */
|
|
270
|
+
labelColumns: Array<string>;
|
|
271
|
+
/* An unmarked, non-relation column that can be sorted on. */
|
|
272
|
+
unmarkedSortColumn: string;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const METHOD_MODELS: Array<MethodModelUnderTest> = [
|
|
276
|
+
{
|
|
277
|
+
name: "UserEmail",
|
|
278
|
+
modelType: UserEmail,
|
|
279
|
+
adminReadableModelType: AdminReadableUserEmail,
|
|
280
|
+
relationColumnName: "userEmail",
|
|
281
|
+
ownerOnlyColumns: ["email", "verificationCode"],
|
|
282
|
+
ownerOnlyColumnsSelectableByOwner: ["email"],
|
|
283
|
+
ownerOnlyColumnReachableThroughRelation: "email",
|
|
284
|
+
labelColumnReachableThroughRelation: "projectId",
|
|
285
|
+
labelColumns: ["userId", "projectId", "isVerified"],
|
|
286
|
+
unmarkedSortColumn: "isVerified",
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
name: "UserSMS",
|
|
290
|
+
modelType: UserSMS,
|
|
291
|
+
adminReadableModelType: AdminReadableUserSMS,
|
|
292
|
+
relationColumnName: "userSms",
|
|
293
|
+
ownerOnlyColumns: ["phone", "verificationCode"],
|
|
294
|
+
ownerOnlyColumnsSelectableByOwner: ["phone"],
|
|
295
|
+
ownerOnlyColumnReachableThroughRelation: "phone",
|
|
296
|
+
labelColumnReachableThroughRelation: "projectId",
|
|
297
|
+
labelColumns: ["userId", "projectId", "isVerified"],
|
|
298
|
+
unmarkedSortColumn: "isVerified",
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
name: "UserCall",
|
|
302
|
+
modelType: UserCall,
|
|
303
|
+
adminReadableModelType: AdminReadableUserCall,
|
|
304
|
+
relationColumnName: "userCall",
|
|
305
|
+
ownerOnlyColumns: ["phone", "verificationCode"],
|
|
306
|
+
ownerOnlyColumnsSelectableByOwner: ["phone"],
|
|
307
|
+
ownerOnlyColumnReachableThroughRelation: "phone",
|
|
308
|
+
labelColumnReachableThroughRelation: "projectId",
|
|
309
|
+
labelColumns: ["userId", "projectId", "isVerified"],
|
|
310
|
+
unmarkedSortColumn: "isVerified",
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
name: "UserPush",
|
|
314
|
+
modelType: UserPush,
|
|
315
|
+
adminReadableModelType: AdminReadableUserPush,
|
|
316
|
+
relationColumnName: "userPush",
|
|
317
|
+
ownerOnlyColumns: ["deviceToken"],
|
|
318
|
+
ownerOnlyColumnsSelectableByOwner: ["deviceToken"],
|
|
319
|
+
ownerOnlyColumnReachableThroughRelation: "deviceToken",
|
|
320
|
+
labelColumnReachableThroughRelation: "deviceName",
|
|
321
|
+
labelColumns: [
|
|
322
|
+
"userId",
|
|
323
|
+
"projectId",
|
|
324
|
+
"isVerified",
|
|
325
|
+
"deviceName",
|
|
326
|
+
"deviceType",
|
|
327
|
+
],
|
|
328
|
+
unmarkedSortColumn: "deviceName",
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
name: "UserWhatsApp",
|
|
332
|
+
modelType: UserWhatsApp,
|
|
333
|
+
adminReadableModelType: AdminReadableUserWhatsApp,
|
|
334
|
+
relationColumnName: "userWhatsApp",
|
|
335
|
+
ownerOnlyColumns: ["phone", "verificationCode"],
|
|
336
|
+
ownerOnlyColumnsSelectableByOwner: ["phone"],
|
|
337
|
+
ownerOnlyColumnReachableThroughRelation: "phone",
|
|
338
|
+
labelColumnReachableThroughRelation: "projectId",
|
|
339
|
+
labelColumns: ["userId", "projectId", "isVerified"],
|
|
340
|
+
unmarkedSortColumn: "isVerified",
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
name: "UserTelegram",
|
|
344
|
+
modelType: UserTelegram,
|
|
345
|
+
adminReadableModelType: AdminReadableUserTelegram,
|
|
346
|
+
relationColumnName: "userTelegram",
|
|
347
|
+
ownerOnlyColumns: [
|
|
348
|
+
"telegramUserHandle",
|
|
349
|
+
"telegramChatId",
|
|
350
|
+
"verificationCode",
|
|
351
|
+
],
|
|
352
|
+
ownerOnlyColumnsSelectableByOwner: [
|
|
353
|
+
"telegramUserHandle",
|
|
354
|
+
"telegramChatId",
|
|
355
|
+
"verificationCode",
|
|
356
|
+
],
|
|
357
|
+
ownerOnlyColumnReachableThroughRelation: "telegramChatId",
|
|
358
|
+
labelColumnReachableThroughRelation: "projectId",
|
|
359
|
+
labelColumns: ["userId", "projectId", "isVerified"],
|
|
360
|
+
unmarkedSortColumn: "isVerified",
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
name: "UserWebhook",
|
|
364
|
+
modelType: UserWebhook,
|
|
365
|
+
adminReadableModelType: AdminReadableUserWebhook,
|
|
366
|
+
relationColumnName: "userWebhook",
|
|
367
|
+
ownerOnlyColumns: ["webhookUrl", "secret"],
|
|
368
|
+
ownerOnlyColumnsSelectableByOwner: ["webhookUrl", "secret"],
|
|
369
|
+
ownerOnlyColumnReachableThroughRelation: "webhookUrl",
|
|
370
|
+
labelColumnReachableThroughRelation: "name",
|
|
371
|
+
labelColumns: ["userId", "projectId", "name"],
|
|
372
|
+
unmarkedSortColumn: "name",
|
|
373
|
+
},
|
|
374
|
+
];
|
|
375
|
+
|
|
376
|
+
/*
|
|
377
|
+
* The marked columns that no permission list lets an ordinary caller select at
|
|
378
|
+
* all. Pinned separately so that the guarded list above stays honest about what
|
|
379
|
+
* this guard is responsible for.
|
|
380
|
+
*/
|
|
381
|
+
const WRITE_ONLY_VERIFICATION_CODE_MODELS: Array<ModelTypeUnderTest> = [
|
|
382
|
+
UserEmail,
|
|
383
|
+
UserSMS,
|
|
384
|
+
UserCall,
|
|
385
|
+
UserWhatsApp,
|
|
386
|
+
];
|
|
387
|
+
|
|
388
|
+
/*
|
|
389
|
+
* Props are rebuilt for every call rather than shared. getUserPermissions()
|
|
390
|
+
* MUTATES the props it is given (it pushes the auto-granted Public and
|
|
391
|
+
* CurrentUser onto the global permission list), so a shared object would carry
|
|
392
|
+
* state between assertions.
|
|
393
|
+
*/
|
|
394
|
+
function makeOwnerProps(): DatabaseCommonInteractionProps {
|
|
395
|
+
return {
|
|
396
|
+
userId: ownerUserId,
|
|
397
|
+
tenantId: projectId,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function makeAdminProps(): DatabaseCommonInteractionProps {
|
|
402
|
+
return {
|
|
403
|
+
userId: adminUserId,
|
|
404
|
+
tenantId: projectId,
|
|
405
|
+
userTenantAccessPermission: {
|
|
406
|
+
[projectId.toString()]: {
|
|
407
|
+
projectId: projectId,
|
|
408
|
+
permissions: [
|
|
409
|
+
{
|
|
410
|
+
permission: Permission.ProjectAdmin,
|
|
411
|
+
labelIds: [],
|
|
412
|
+
isBlockPermission: false,
|
|
413
|
+
_type: "UserPermission",
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
_type: "UserTenantAccessPermission",
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/*
|
|
423
|
+
* An API key carrying a project role and no user identity at all. There is no
|
|
424
|
+
* id such a caller could be pinned to, so every marked column must refuse.
|
|
425
|
+
*/
|
|
426
|
+
function makeApiKeyAdminProps(): DatabaseCommonInteractionProps {
|
|
427
|
+
return {
|
|
428
|
+
userType: UserType.API,
|
|
429
|
+
tenantId: projectId,
|
|
430
|
+
userTenantAccessPermission: {
|
|
431
|
+
[projectId.toString()]: {
|
|
432
|
+
projectId: projectId,
|
|
433
|
+
permissions: [
|
|
434
|
+
{
|
|
435
|
+
permission: Permission.ProjectAdmin,
|
|
436
|
+
labelIds: [],
|
|
437
|
+
isBlockPermission: false,
|
|
438
|
+
_type: "UserPermission",
|
|
439
|
+
},
|
|
440
|
+
],
|
|
441
|
+
_type: "UserTenantAccessPermission",
|
|
442
|
+
},
|
|
443
|
+
},
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function makeRootProps(): DatabaseCommonInteractionProps {
|
|
448
|
+
return {
|
|
449
|
+
isRoot: true,
|
|
450
|
+
tenantId: projectId,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
type ReadCheck = (
|
|
455
|
+
modelType: ModelTypeUnderTest,
|
|
456
|
+
query: Record<string, unknown>,
|
|
457
|
+
select: Record<string, unknown> | null,
|
|
458
|
+
props: DatabaseCommonInteractionProps,
|
|
459
|
+
) => Promise<CheckReadPermissionType<BaseModel>>;
|
|
460
|
+
|
|
461
|
+
/*
|
|
462
|
+
* The real entry point every read in the product goes through - DatabaseService
|
|
463
|
+
* calls exactly this before handing anything to TypeORM.
|
|
464
|
+
*/
|
|
465
|
+
const checkRead: ReadCheck = (
|
|
466
|
+
modelType: ModelTypeUnderTest,
|
|
467
|
+
query: Record<string, unknown>,
|
|
468
|
+
select: Record<string, unknown> | null,
|
|
469
|
+
props: DatabaseCommonInteractionProps,
|
|
470
|
+
): Promise<CheckReadPermissionType<BaseModel>> => {
|
|
471
|
+
return ModelPermission.checkReadQueryPermission<BaseModel>(
|
|
472
|
+
modelType,
|
|
473
|
+
query as Query<BaseModel>,
|
|
474
|
+
select as Select<BaseModel> | null,
|
|
475
|
+
props,
|
|
476
|
+
);
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
describe("route 1 - a marked column named directly in the select", () => {
|
|
480
|
+
it.each(METHOD_MODELS)(
|
|
481
|
+
"lets the owner read every owner-only column on $name",
|
|
482
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
483
|
+
/*
|
|
484
|
+
* The owner sends no ownership filter at all here. They do not need to:
|
|
485
|
+
* the method models are CurrentUser-only, so TenantPermission stamps
|
|
486
|
+
* `userId = me` onto the query before the select is ever inspected, and
|
|
487
|
+
* that stamp is what pins the read.
|
|
488
|
+
*/
|
|
489
|
+
for (const columnName of model.ownerOnlyColumnsSelectableByOwner) {
|
|
490
|
+
const result: CheckReadPermissionType<BaseModel> = await checkRead(
|
|
491
|
+
model.modelType,
|
|
492
|
+
{},
|
|
493
|
+
{ [columnName]: true },
|
|
494
|
+
makeOwnerProps(),
|
|
495
|
+
);
|
|
496
|
+
|
|
497
|
+
expect((result.select as Record<string, unknown>)[columnName]).toBe(
|
|
498
|
+
true,
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
},
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
it.each(METHOD_MODELS)(
|
|
505
|
+
"lets the owner read every owner-only column on $name when they name their own id",
|
|
506
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
507
|
+
/*
|
|
508
|
+
* Only the subset the owner may actually select: a verificationCode is
|
|
509
|
+
* read: [] for everybody, so demanding it here would assert a leak.
|
|
510
|
+
*/
|
|
511
|
+
for (const columnName of model.ownerOnlyColumnsSelectableByOwner) {
|
|
512
|
+
await expect(
|
|
513
|
+
checkRead(
|
|
514
|
+
model.modelType,
|
|
515
|
+
{ userId: ownerUserId },
|
|
516
|
+
{ [columnName]: true },
|
|
517
|
+
makeOwnerProps(),
|
|
518
|
+
),
|
|
519
|
+
).resolves.toBeDefined();
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
it.each(METHOD_MODELS)(
|
|
525
|
+
"refuses an admin reading another member's owner-only columns on $name",
|
|
526
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
527
|
+
for (const columnName of model.ownerOnlyColumns) {
|
|
528
|
+
await expect(
|
|
529
|
+
checkRead(
|
|
530
|
+
model.adminReadableModelType,
|
|
531
|
+
{ userId: otherUserId },
|
|
532
|
+
{ [columnName]: true },
|
|
533
|
+
makeAdminProps(),
|
|
534
|
+
),
|
|
535
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
);
|
|
539
|
+
|
|
540
|
+
it.each(METHOD_MODELS)(
|
|
541
|
+
"refuses an admin sweeping $name for owner-only columns across the whole project",
|
|
542
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
543
|
+
/*
|
|
544
|
+
* The most valuable version of the attack asks for no user at all: one
|
|
545
|
+
* request, every row in the project, every credential on it.
|
|
546
|
+
*/
|
|
547
|
+
for (const columnName of model.ownerOnlyColumns) {
|
|
548
|
+
await expect(
|
|
549
|
+
checkRead(
|
|
550
|
+
model.adminReadableModelType,
|
|
551
|
+
{},
|
|
552
|
+
{ [columnName]: true },
|
|
553
|
+
makeAdminProps(),
|
|
554
|
+
),
|
|
555
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
it.each(METHOD_MODELS)(
|
|
561
|
+
"lets an admin read their OWN owner-only columns on $name",
|
|
562
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
563
|
+
/*
|
|
564
|
+
* Being an administrator does not cost you your own settings page. The
|
|
565
|
+
* rule is about which ROW is being read, not about who is asking.
|
|
566
|
+
*/
|
|
567
|
+
/*
|
|
568
|
+
* Only the subset the owner may actually select: a verificationCode is
|
|
569
|
+
* read: [] for everybody, so demanding it here would assert a leak.
|
|
570
|
+
*/
|
|
571
|
+
for (const columnName of model.ownerOnlyColumnsSelectableByOwner) {
|
|
572
|
+
await expect(
|
|
573
|
+
checkRead(
|
|
574
|
+
model.adminReadableModelType,
|
|
575
|
+
{ userId: adminUserId },
|
|
576
|
+
{ [columnName]: true },
|
|
577
|
+
makeAdminProps(),
|
|
578
|
+
),
|
|
579
|
+
).resolves.toBeDefined();
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
it.each(METHOD_MODELS)(
|
|
585
|
+
"refuses an ownership filter on $name that is a query operator rather than an id",
|
|
586
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
587
|
+
/*
|
|
588
|
+
* NotEqual stringifies to the id it wraps, so a guard comparing only
|
|
589
|
+
* string values would read `userId != me` as `userId = me` and hand back
|
|
590
|
+
* every OTHER row in the project - the exact inversion of what was asked
|
|
591
|
+
* for. The type is checked before the value.
|
|
592
|
+
*/
|
|
593
|
+
await expect(
|
|
594
|
+
checkRead(
|
|
595
|
+
model.adminReadableModelType,
|
|
596
|
+
{ userId: new NotEqual<string>(adminUserId.toString()) },
|
|
597
|
+
{ [model.ownerOnlyColumnReachableThroughRelation]: true },
|
|
598
|
+
makeAdminProps(),
|
|
599
|
+
),
|
|
600
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
601
|
+
},
|
|
602
|
+
);
|
|
603
|
+
|
|
604
|
+
it.each(METHOD_MODELS)(
|
|
605
|
+
"refuses an API key with a project role reading owner-only columns on $name",
|
|
606
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
607
|
+
/*
|
|
608
|
+
* An API key holds project permissions and no user identity. There is no
|
|
609
|
+
* id to pin to, so there is no pinning, so there is no read. Fail closed.
|
|
610
|
+
*/
|
|
611
|
+
await expect(
|
|
612
|
+
checkRead(
|
|
613
|
+
model.adminReadableModelType,
|
|
614
|
+
{},
|
|
615
|
+
{ [model.ownerOnlyColumnReachableThroughRelation]: true },
|
|
616
|
+
makeApiKeyAdminProps(),
|
|
617
|
+
),
|
|
618
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
619
|
+
},
|
|
620
|
+
);
|
|
621
|
+
|
|
622
|
+
it.each(METHOD_MODELS)(
|
|
623
|
+
"still lets an admin read the unmarked label columns of another member's $name",
|
|
624
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
625
|
+
/*
|
|
626
|
+
* This is the half of Phase 3 that has to keep working. An admin who
|
|
627
|
+
* cannot see that a row exists, what kind of thing it is and whether it
|
|
628
|
+
* is verified cannot audit anybody's on-call setup - the feature would be
|
|
629
|
+
* gone. Only the credential is withheld.
|
|
630
|
+
*/
|
|
631
|
+
await expect(
|
|
632
|
+
checkRead(
|
|
633
|
+
model.adminReadableModelType,
|
|
634
|
+
{ userId: otherUserId },
|
|
635
|
+
/*
|
|
636
|
+
* The label columns come from the fixture rather than a hardcoded
|
|
637
|
+
* list, because they genuinely differ per model: UserWebhook has no
|
|
638
|
+
* isVerified column at all - a webhook skips verification - so naming
|
|
639
|
+
* it here would fail that model for a reason that has nothing to do
|
|
640
|
+
* with this guard.
|
|
641
|
+
*/
|
|
642
|
+
model.labelColumns.reduce(
|
|
643
|
+
(
|
|
644
|
+
selected: Record<string, boolean>,
|
|
645
|
+
columnName: string,
|
|
646
|
+
): Record<string, boolean> => {
|
|
647
|
+
selected[columnName] = true;
|
|
648
|
+
|
|
649
|
+
return selected;
|
|
650
|
+
},
|
|
651
|
+
{ _id: true } as Record<string, boolean>,
|
|
652
|
+
),
|
|
653
|
+
makeAdminProps(),
|
|
654
|
+
),
|
|
655
|
+
).resolves.toBeDefined();
|
|
656
|
+
},
|
|
657
|
+
);
|
|
658
|
+
|
|
659
|
+
it.each(METHOD_MODELS)(
|
|
660
|
+
"lets root read owner-only columns on $name with no ownership filter",
|
|
661
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
662
|
+
/*
|
|
663
|
+
* Delivery reads these exact columns as root in order to actually send
|
|
664
|
+
* the notification. A phone number the pager cannot read is a phone that
|
|
665
|
+
* never rings, so root has to short-circuit before any of this.
|
|
666
|
+
*/
|
|
667
|
+
for (const columnName of model.ownerOnlyColumns) {
|
|
668
|
+
await expect(
|
|
669
|
+
checkRead(
|
|
670
|
+
model.modelType,
|
|
671
|
+
{},
|
|
672
|
+
{ [columnName]: true },
|
|
673
|
+
makeRootProps(),
|
|
674
|
+
),
|
|
675
|
+
).resolves.toBeDefined();
|
|
676
|
+
}
|
|
677
|
+
},
|
|
678
|
+
);
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
describe("route 2 - a marked column reached through a relation", () => {
|
|
682
|
+
it.each(METHOD_MODELS)(
|
|
683
|
+
"lets the owner read $name's identifier through the rule relation",
|
|
684
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
685
|
+
/*
|
|
686
|
+
* "Email: jane@example.com" on a user's own rule table. This is the
|
|
687
|
+
* legitimate use of canReadOnRelationQuery, and it must survive.
|
|
688
|
+
*/
|
|
689
|
+
const result: CheckReadPermissionType<BaseModel> = await checkRead(
|
|
690
|
+
AdminReadableRuleModel,
|
|
691
|
+
{},
|
|
692
|
+
{
|
|
693
|
+
[model.relationColumnName]: {
|
|
694
|
+
[model.ownerOnlyColumnReachableThroughRelation]: true,
|
|
695
|
+
},
|
|
696
|
+
},
|
|
697
|
+
makeOwnerProps(),
|
|
698
|
+
);
|
|
699
|
+
|
|
700
|
+
expect(
|
|
701
|
+
(result.relationSelect as Record<string, unknown>)[
|
|
702
|
+
model.relationColumnName
|
|
703
|
+
],
|
|
704
|
+
).toBe(true);
|
|
705
|
+
},
|
|
706
|
+
);
|
|
707
|
+
|
|
708
|
+
it.each(METHOD_MODELS)(
|
|
709
|
+
"refuses an admin reading $name's identifier through another member's rule",
|
|
710
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
711
|
+
/*
|
|
712
|
+
* THE BLOCKER, EXACTLY. Nothing about the method table was widened here -
|
|
713
|
+
* only the rule table was - and the credential still walks out through
|
|
714
|
+
* the join, because checkRelationQueryPermission used to `continue` past
|
|
715
|
+
* every permission check the moment canReadOnRelationQuery was set. The
|
|
716
|
+
* outer query is the only thing that knows these related rows are not the
|
|
717
|
+
* caller's, which is why it has to be threaded into the traversal.
|
|
718
|
+
*/
|
|
719
|
+
await expect(
|
|
720
|
+
checkRead(
|
|
721
|
+
AdminReadableRuleModel,
|
|
722
|
+
{ userId: otherUserId },
|
|
723
|
+
{
|
|
724
|
+
[model.relationColumnName]: {
|
|
725
|
+
[model.ownerOnlyColumnReachableThroughRelation]: true,
|
|
726
|
+
},
|
|
727
|
+
},
|
|
728
|
+
makeAdminProps(),
|
|
729
|
+
),
|
|
730
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
731
|
+
},
|
|
732
|
+
);
|
|
733
|
+
|
|
734
|
+
it.each(METHOD_MODELS)(
|
|
735
|
+
"refuses an admin sweeping every rule in the project for $name identifiers",
|
|
736
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
737
|
+
await expect(
|
|
738
|
+
checkRead(
|
|
739
|
+
AdminReadableRuleModel,
|
|
740
|
+
{},
|
|
741
|
+
{
|
|
742
|
+
[model.relationColumnName]: {
|
|
743
|
+
[model.ownerOnlyColumnReachableThroughRelation]: true,
|
|
744
|
+
},
|
|
745
|
+
},
|
|
746
|
+
makeAdminProps(),
|
|
747
|
+
),
|
|
748
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
749
|
+
},
|
|
750
|
+
);
|
|
751
|
+
|
|
752
|
+
it.each(METHOD_MODELS)(
|
|
753
|
+
"lets an admin read $name's identifier through their OWN rule",
|
|
754
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
755
|
+
await expect(
|
|
756
|
+
checkRead(
|
|
757
|
+
AdminReadableRuleModel,
|
|
758
|
+
{ userId: adminUserId },
|
|
759
|
+
{
|
|
760
|
+
[model.relationColumnName]: {
|
|
761
|
+
[model.ownerOnlyColumnReachableThroughRelation]: true,
|
|
762
|
+
},
|
|
763
|
+
},
|
|
764
|
+
makeAdminProps(),
|
|
765
|
+
),
|
|
766
|
+
).resolves.toBeDefined();
|
|
767
|
+
},
|
|
768
|
+
);
|
|
769
|
+
|
|
770
|
+
it.each(METHOD_MODELS)(
|
|
771
|
+
"refuses a relation read of $name when the ownership filter is a query operator",
|
|
772
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
773
|
+
await expect(
|
|
774
|
+
checkRead(
|
|
775
|
+
AdminReadableRuleModel,
|
|
776
|
+
{ userId: new NotEqual<string>(adminUserId.toString()) },
|
|
777
|
+
{
|
|
778
|
+
[model.relationColumnName]: {
|
|
779
|
+
[model.ownerOnlyColumnReachableThroughRelation]: true,
|
|
780
|
+
},
|
|
781
|
+
},
|
|
782
|
+
makeAdminProps(),
|
|
783
|
+
),
|
|
784
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
785
|
+
},
|
|
786
|
+
);
|
|
787
|
+
|
|
788
|
+
it.each(METHOD_MODELS)(
|
|
789
|
+
"refuses an API key with a project role reading $name through a rule",
|
|
790
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
791
|
+
await expect(
|
|
792
|
+
checkRead(
|
|
793
|
+
AdminReadableRuleModel,
|
|
794
|
+
{},
|
|
795
|
+
{
|
|
796
|
+
[model.relationColumnName]: {
|
|
797
|
+
[model.ownerOnlyColumnReachableThroughRelation]: true,
|
|
798
|
+
},
|
|
799
|
+
},
|
|
800
|
+
makeApiKeyAdminProps(),
|
|
801
|
+
),
|
|
802
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
803
|
+
},
|
|
804
|
+
);
|
|
805
|
+
|
|
806
|
+
it.each(METHOD_MODELS)(
|
|
807
|
+
"still lets an admin label another member's rule with $name's unmarked column",
|
|
808
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
809
|
+
/*
|
|
810
|
+
* The admin rule table still renders "Webhook: My Slack" and "Push:
|
|
811
|
+
* Jane's iPhone". Naming the method is not the same as being handed it.
|
|
812
|
+
*/
|
|
813
|
+
await expect(
|
|
814
|
+
checkRead(
|
|
815
|
+
AdminReadableRuleModel,
|
|
816
|
+
{ userId: otherUserId },
|
|
817
|
+
{
|
|
818
|
+
_id: true,
|
|
819
|
+
[model.relationColumnName]: {
|
|
820
|
+
[model.labelColumnReachableThroughRelation]: true,
|
|
821
|
+
},
|
|
822
|
+
},
|
|
823
|
+
makeAdminProps(),
|
|
824
|
+
),
|
|
825
|
+
).resolves.toBeDefined();
|
|
826
|
+
},
|
|
827
|
+
);
|
|
828
|
+
|
|
829
|
+
it.each(METHOD_MODELS)(
|
|
830
|
+
"refuses the whole select when a marked $name column rides along with unmarked ones",
|
|
831
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
832
|
+
/*
|
|
833
|
+
* A refusal that only fires for a select containing nothing BUT the
|
|
834
|
+
* credential is a refusal an attacker routes around by asking for one
|
|
835
|
+
* extra column.
|
|
836
|
+
*/
|
|
837
|
+
await expect(
|
|
838
|
+
checkRead(
|
|
839
|
+
AdminReadableRuleModel,
|
|
840
|
+
{ userId: otherUserId },
|
|
841
|
+
{
|
|
842
|
+
_id: true,
|
|
843
|
+
[model.relationColumnName]: {
|
|
844
|
+
[model.labelColumnReachableThroughRelation]: true,
|
|
845
|
+
[model.ownerOnlyColumnReachableThroughRelation]: true,
|
|
846
|
+
},
|
|
847
|
+
},
|
|
848
|
+
makeAdminProps(),
|
|
849
|
+
),
|
|
850
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
851
|
+
},
|
|
852
|
+
);
|
|
853
|
+
|
|
854
|
+
it("lets root read every method identifier through any rule", async () => {
|
|
855
|
+
for (const model of METHOD_MODELS) {
|
|
856
|
+
await expect(
|
|
857
|
+
checkRead(
|
|
858
|
+
AdminReadableRuleModel,
|
|
859
|
+
{},
|
|
860
|
+
{
|
|
861
|
+
[model.relationColumnName]: {
|
|
862
|
+
[model.ownerOnlyColumnReachableThroughRelation]: true,
|
|
863
|
+
},
|
|
864
|
+
},
|
|
865
|
+
makeRootProps(),
|
|
866
|
+
),
|
|
867
|
+
).resolves.toBeDefined();
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
describe("route 3 - a marked column injected into the select as a sort key", () => {
|
|
873
|
+
/*
|
|
874
|
+
* DatabaseService adds sorted columns to the select AFTER ModelPermission has
|
|
875
|
+
* finished, validating them only with hasColumn/isEntityColumn. That is the
|
|
876
|
+
* gap: the permission layer never sees the column at all. The private method
|
|
877
|
+
* is called directly here because the public path (_findBy) needs a live
|
|
878
|
+
* database connection, and the injection is the whole of the behaviour under
|
|
879
|
+
* test - this is the production method, not a restatement of it.
|
|
880
|
+
*/
|
|
881
|
+
type SortInjector = {
|
|
882
|
+
addSortColumnsToSelect: (findBy: FindBy<BaseModel>) => Array<string>;
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
function injectSortColumns(
|
|
886
|
+
modelType: ModelTypeUnderTest,
|
|
887
|
+
findBy: FindBy<BaseModel>,
|
|
888
|
+
): Array<string> {
|
|
889
|
+
const service: DatabaseService<BaseModel> = new DatabaseService<BaseModel>(
|
|
890
|
+
modelType,
|
|
891
|
+
);
|
|
892
|
+
|
|
893
|
+
return (service as unknown as SortInjector).addSortColumnsToSelect(findBy);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
it.each(METHOD_MODELS)(
|
|
897
|
+
"does not smuggle an owner-only $name column into the select via sort",
|
|
898
|
+
(model: MethodModelUnderTest): void => {
|
|
899
|
+
for (const columnName of model.ownerOnlyColumns) {
|
|
900
|
+
const findBy: FindBy<BaseModel> = {
|
|
901
|
+
query: {},
|
|
902
|
+
select: { _id: true } as Select<BaseModel>,
|
|
903
|
+
sort: { [columnName]: SortOrder.Ascending } as Record<
|
|
904
|
+
string,
|
|
905
|
+
SortOrder
|
|
906
|
+
>,
|
|
907
|
+
limit: 10,
|
|
908
|
+
skip: 0,
|
|
909
|
+
props: makeOwnerProps(),
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
expect(injectSortColumns(model.modelType, findBy)).toEqual([]);
|
|
913
|
+
expect(
|
|
914
|
+
(findBy.select as Record<string, unknown>)[columnName],
|
|
915
|
+
).toBeUndefined();
|
|
916
|
+
}
|
|
917
|
+
},
|
|
918
|
+
);
|
|
919
|
+
|
|
920
|
+
it.each(METHOD_MODELS)(
|
|
921
|
+
"still adds an unmarked sorted column on $name to the select",
|
|
922
|
+
(model: MethodModelUnderTest): void => {
|
|
923
|
+
/*
|
|
924
|
+
* The mechanism this method exists for has to keep working, or the fix
|
|
925
|
+
* would just be "delete the feature". Sorting on an ordinary column while
|
|
926
|
+
* a relation is selected still needs the column in the select or TypeORM
|
|
927
|
+
* fails the query outright.
|
|
928
|
+
*/
|
|
929
|
+
const findBy: FindBy<BaseModel> = {
|
|
930
|
+
query: {},
|
|
931
|
+
select: { _id: true } as Select<BaseModel>,
|
|
932
|
+
// Per-model: UserWebhook has no isVerified column to sort on.
|
|
933
|
+
sort: { [model.unmarkedSortColumn]: SortOrder.Ascending } as Record<
|
|
934
|
+
string,
|
|
935
|
+
SortOrder
|
|
936
|
+
>,
|
|
937
|
+
limit: 10,
|
|
938
|
+
skip: 0,
|
|
939
|
+
props: makeOwnerProps(),
|
|
940
|
+
};
|
|
941
|
+
|
|
942
|
+
expect(injectSortColumns(model.modelType, findBy)).toEqual([
|
|
943
|
+
model.unmarkedSortColumn,
|
|
944
|
+
]);
|
|
945
|
+
expect(
|
|
946
|
+
(findBy.select as Record<string, unknown>)[model.unmarkedSortColumn],
|
|
947
|
+
).toBe(true);
|
|
948
|
+
},
|
|
949
|
+
);
|
|
950
|
+
|
|
951
|
+
it("leaves a marked column alone when the caller already selected it legitimately", () => {
|
|
952
|
+
/*
|
|
953
|
+
* An owner who passed route 1 has the column in their select already, so
|
|
954
|
+
* the injector never reaches it - the exclusion costs a legitimate reader
|
|
955
|
+
* nothing at all.
|
|
956
|
+
*/
|
|
957
|
+
const findBy: FindBy<BaseModel> = {
|
|
958
|
+
query: {},
|
|
959
|
+
select: { _id: true, webhookUrl: true } as Select<BaseModel>,
|
|
960
|
+
sort: { webhookUrl: SortOrder.Ascending } as Record<string, SortOrder>,
|
|
961
|
+
limit: 10,
|
|
962
|
+
skip: 0,
|
|
963
|
+
props: makeOwnerProps(),
|
|
964
|
+
};
|
|
965
|
+
|
|
966
|
+
expect(injectSortColumns(UserWebhook, findBy)).toEqual([]);
|
|
967
|
+
expect((findBy.select as Record<string, unknown>)["webhookUrl"]).toBe(true);
|
|
968
|
+
});
|
|
969
|
+
|
|
970
|
+
it("still injects marked sort columns for root", () => {
|
|
971
|
+
const findBy: FindBy<BaseModel> = {
|
|
972
|
+
query: {},
|
|
973
|
+
select: { _id: true } as Select<BaseModel>,
|
|
974
|
+
sort: { webhookUrl: SortOrder.Ascending } as Record<string, SortOrder>,
|
|
975
|
+
limit: 10,
|
|
976
|
+
skip: 0,
|
|
977
|
+
props: makeRootProps(),
|
|
978
|
+
};
|
|
979
|
+
|
|
980
|
+
expect(injectSortColumns(UserWebhook, findBy)).toEqual(["webhookUrl"]);
|
|
981
|
+
expect((findBy.select as Record<string, unknown>)["webhookUrl"]).toBe(true);
|
|
982
|
+
});
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
describe("route 4 - a marked column used as a query predicate", () => {
|
|
986
|
+
it.each(METHOD_MODELS)(
|
|
987
|
+
"lets the owner filter their own $name rows on an owner-only column",
|
|
988
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
989
|
+
await expect(
|
|
990
|
+
checkRead(
|
|
991
|
+
model.modelType,
|
|
992
|
+
{ [model.ownerOnlyColumnReachableThroughRelation]: "probe-value" },
|
|
993
|
+
{ _id: true },
|
|
994
|
+
makeOwnerProps(),
|
|
995
|
+
),
|
|
996
|
+
).resolves.toBeDefined();
|
|
997
|
+
},
|
|
998
|
+
);
|
|
999
|
+
|
|
1000
|
+
it.each(METHOD_MODELS)(
|
|
1001
|
+
"refuses an admin probing $name for a value across the project",
|
|
1002
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
1003
|
+
/*
|
|
1004
|
+
* Nothing is selected here. Equality on a secret is a confirm/deny
|
|
1005
|
+
* oracle, and a few thousand of these read the value out without a single
|
|
1006
|
+
* row ever being returned - so a WHERE is held to the same standard as a
|
|
1007
|
+
* SELECT.
|
|
1008
|
+
*/
|
|
1009
|
+
await expect(
|
|
1010
|
+
checkRead(
|
|
1011
|
+
model.adminReadableModelType,
|
|
1012
|
+
{ [model.ownerOnlyColumnReachableThroughRelation]: "probe-value" },
|
|
1013
|
+
{ _id: true },
|
|
1014
|
+
makeAdminProps(),
|
|
1015
|
+
),
|
|
1016
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
1017
|
+
},
|
|
1018
|
+
);
|
|
1019
|
+
|
|
1020
|
+
it.each(METHOD_MODELS)(
|
|
1021
|
+
"refuses an admin probing another member's $name rows",
|
|
1022
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
1023
|
+
await expect(
|
|
1024
|
+
checkRead(
|
|
1025
|
+
model.adminReadableModelType,
|
|
1026
|
+
{
|
|
1027
|
+
userId: otherUserId,
|
|
1028
|
+
[model.ownerOnlyColumnReachableThroughRelation]: "probe-value",
|
|
1029
|
+
},
|
|
1030
|
+
{ _id: true },
|
|
1031
|
+
makeAdminProps(),
|
|
1032
|
+
),
|
|
1033
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
1034
|
+
},
|
|
1035
|
+
);
|
|
1036
|
+
|
|
1037
|
+
it.each(METHOD_MODELS)(
|
|
1038
|
+
"lets an admin filter their OWN $name rows on an owner-only column",
|
|
1039
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
1040
|
+
await expect(
|
|
1041
|
+
checkRead(
|
|
1042
|
+
model.adminReadableModelType,
|
|
1043
|
+
{
|
|
1044
|
+
userId: adminUserId,
|
|
1045
|
+
[model.ownerOnlyColumnReachableThroughRelation]: "probe-value",
|
|
1046
|
+
},
|
|
1047
|
+
{ _id: true },
|
|
1048
|
+
makeAdminProps(),
|
|
1049
|
+
),
|
|
1050
|
+
).resolves.toBeDefined();
|
|
1051
|
+
},
|
|
1052
|
+
);
|
|
1053
|
+
|
|
1054
|
+
it.each(METHOD_MODELS)(
|
|
1055
|
+
"refuses an admin probing $name through a relation filter on a rule",
|
|
1056
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
1057
|
+
/*
|
|
1058
|
+
* The predicate route has the same nested variant as the select route:
|
|
1059
|
+
* `{ userWebhook: { webhookUrl: x } }` probes the identical value one
|
|
1060
|
+
* level out.
|
|
1061
|
+
*/
|
|
1062
|
+
await expect(
|
|
1063
|
+
checkRead(
|
|
1064
|
+
AdminReadableRuleModel,
|
|
1065
|
+
{
|
|
1066
|
+
userId: otherUserId,
|
|
1067
|
+
[model.relationColumnName]: {
|
|
1068
|
+
[model.ownerOnlyColumnReachableThroughRelation]: "probe-value",
|
|
1069
|
+
},
|
|
1070
|
+
},
|
|
1071
|
+
{ _id: true },
|
|
1072
|
+
makeAdminProps(),
|
|
1073
|
+
),
|
|
1074
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
1075
|
+
},
|
|
1076
|
+
);
|
|
1077
|
+
|
|
1078
|
+
it.each(METHOD_MODELS)(
|
|
1079
|
+
"lets the owner filter their own rules through a $name relation predicate",
|
|
1080
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
1081
|
+
await expect(
|
|
1082
|
+
checkRead(
|
|
1083
|
+
AdminReadableRuleModel,
|
|
1084
|
+
{
|
|
1085
|
+
[model.relationColumnName]: {
|
|
1086
|
+
[model.ownerOnlyColumnReachableThroughRelation]: "probe-value",
|
|
1087
|
+
},
|
|
1088
|
+
},
|
|
1089
|
+
{ _id: true },
|
|
1090
|
+
makeOwnerProps(),
|
|
1091
|
+
),
|
|
1092
|
+
).resolves.toBeDefined();
|
|
1093
|
+
},
|
|
1094
|
+
);
|
|
1095
|
+
|
|
1096
|
+
it.each(METHOD_MODELS)(
|
|
1097
|
+
"lets root probe $name on an owner-only column",
|
|
1098
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
1099
|
+
await expect(
|
|
1100
|
+
checkRead(
|
|
1101
|
+
model.modelType,
|
|
1102
|
+
{ [model.ownerOnlyColumnReachableThroughRelation]: "probe-value" },
|
|
1103
|
+
{ _id: true },
|
|
1104
|
+
makeRootProps(),
|
|
1105
|
+
),
|
|
1106
|
+
).resolves.toBeDefined();
|
|
1107
|
+
},
|
|
1108
|
+
);
|
|
1109
|
+
});
|
|
1110
|
+
|
|
1111
|
+
describe("the verification codes nobody may read, owner included", () => {
|
|
1112
|
+
/*
|
|
1113
|
+
* These four columns are the one place where @OwnerOnlyColumn is NOT the thing
|
|
1114
|
+
* doing the work, and that is worth pinning explicitly.
|
|
1115
|
+
*
|
|
1116
|
+
* A live verification code is not a privacy question, it is an account-takeover
|
|
1117
|
+
* one: reading somebody's code is claiming their notification channel, and
|
|
1118
|
+
* claiming their channel is claiming their pages. So the column list refuses
|
|
1119
|
+
* EVERYONE - `read: []` - rather than refusing everyone-except-the-owner. The
|
|
1120
|
+
* owner has no need to read it back either; they received it out of band, and
|
|
1121
|
+
* they submit it rather than fetch it.
|
|
1122
|
+
*
|
|
1123
|
+
* The @OwnerOnlyColumn marker sits on top as belt and braces. If somebody later
|
|
1124
|
+
* widens that read list - to build an admin "resend code" screen, say - the
|
|
1125
|
+
* marker is what stops the widening from silently becoming cross-user, and
|
|
1126
|
+
* these assertions are what tell them the empty list was deliberate rather than
|
|
1127
|
+
* an oversight.
|
|
1128
|
+
*/
|
|
1129
|
+
it.each(WRITE_ONLY_VERIFICATION_CODE_MODELS)(
|
|
1130
|
+
"refuses even the OWNER selecting verificationCode on %p",
|
|
1131
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
1132
|
+
await expect(
|
|
1133
|
+
checkRead(
|
|
1134
|
+
modelType,
|
|
1135
|
+
{ userId: ownerUserId },
|
|
1136
|
+
{ verificationCode: true },
|
|
1137
|
+
makeOwnerProps(),
|
|
1138
|
+
),
|
|
1139
|
+
).rejects.toThrow();
|
|
1140
|
+
},
|
|
1141
|
+
);
|
|
1142
|
+
|
|
1143
|
+
it.each(WRITE_ONLY_VERIFICATION_CODE_MODELS)(
|
|
1144
|
+
"refuses an administrator selecting verificationCode on another member's %p",
|
|
1145
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
1146
|
+
await expect(
|
|
1147
|
+
checkRead(
|
|
1148
|
+
modelType,
|
|
1149
|
+
{ userId: ownerUserId },
|
|
1150
|
+
{ verificationCode: true },
|
|
1151
|
+
makeAdminProps(),
|
|
1152
|
+
),
|
|
1153
|
+
).rejects.toThrow();
|
|
1154
|
+
},
|
|
1155
|
+
);
|
|
1156
|
+
|
|
1157
|
+
it.each(WRITE_ONLY_VERIFICATION_CODE_MODELS)(
|
|
1158
|
+
"still lets the verification flow itself read it as root on %p",
|
|
1159
|
+
async (modelType: ModelTypeUnderTest): Promise<void> => {
|
|
1160
|
+
/*
|
|
1161
|
+
* The code has to be readable by SOMETHING or verification cannot work.
|
|
1162
|
+
* That something is the server verifying a submitted code, which runs as
|
|
1163
|
+
* root and short-circuits every check above. If this ever starts failing,
|
|
1164
|
+
* nobody can verify a notification method again.
|
|
1165
|
+
*/
|
|
1166
|
+
await expect(
|
|
1167
|
+
checkRead(
|
|
1168
|
+
modelType,
|
|
1169
|
+
{ userId: ownerUserId },
|
|
1170
|
+
{ verificationCode: true },
|
|
1171
|
+
makeRootProps(),
|
|
1172
|
+
),
|
|
1173
|
+
).resolves.toBeDefined();
|
|
1174
|
+
},
|
|
1175
|
+
);
|
|
1176
|
+
});
|
|
1177
|
+
|
|
1178
|
+
describe("the production models are still owner-scoped without any of this", () => {
|
|
1179
|
+
it.each(METHOD_MODELS)(
|
|
1180
|
+
"refuses a plain member naming another user on $name outright",
|
|
1181
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
1182
|
+
/*
|
|
1183
|
+
* The owner-only guard is the second lock, not the first. On the
|
|
1184
|
+
* production models the table read is still [CurrentUser], so
|
|
1185
|
+
* TenantPermission rejects a member who names somebody else before the
|
|
1186
|
+
* select is ever considered. Phase 3 removes that first lock for admins
|
|
1187
|
+
* on purpose; this test is here so that a future change which removes it
|
|
1188
|
+
* for everyone is not mistaken for a passing suite.
|
|
1189
|
+
*/
|
|
1190
|
+
await expect(
|
|
1191
|
+
checkRead(
|
|
1192
|
+
model.modelType,
|
|
1193
|
+
{ userId: otherUserId },
|
|
1194
|
+
{ _id: true },
|
|
1195
|
+
makeOwnerProps(),
|
|
1196
|
+
),
|
|
1197
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
1198
|
+
},
|
|
1199
|
+
);
|
|
1200
|
+
|
|
1201
|
+
it.each(METHOD_MODELS)(
|
|
1202
|
+
"refuses a plain member naming another user on the admin-readable $name too",
|
|
1203
|
+
async (model: MethodModelUnderTest): Promise<void> => {
|
|
1204
|
+
/*
|
|
1205
|
+
* Widening the table read to ProjectAdmin does not widen it to everybody:
|
|
1206
|
+
* a member holding no role still intersects on CurrentUser alone and is
|
|
1207
|
+
* still force-scoped to their own rows.
|
|
1208
|
+
*/
|
|
1209
|
+
await expect(
|
|
1210
|
+
checkRead(
|
|
1211
|
+
model.adminReadableModelType,
|
|
1212
|
+
{ userId: otherUserId },
|
|
1213
|
+
{ _id: true },
|
|
1214
|
+
makeOwnerProps(),
|
|
1215
|
+
),
|
|
1216
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
1217
|
+
},
|
|
1218
|
+
);
|
|
1219
|
+
});
|