@oneuptime/common 12.0.5 → 12.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/AIRun.ts +33 -0
- package/Models/DatabaseModels/DataSource.ts +744 -0
- package/Models/DatabaseModels/Index.ts +3 -0
- package/Models/DatabaseModels/ProjectCallSMSConfig.ts +10 -2
- package/Models/DatabaseModels/User.ts +2 -0
- package/Models/DatabaseModels/UserOnCallLog.ts +2 -0
- package/Models/DatabaseModels/UserOnCallLogTimeline.ts +2 -0
- package/Models/DatabaseModels/UserSession.ts +2 -0
- package/Models/DatabaseModels/UserTotpAuth.ts +6 -4
- package/Models/DatabaseModels/UserWebAuthn.ts +5 -3
- package/Server/API/AIInsightAPI.ts +47 -4
- package/Server/API/AIInvestigationAPI.ts +25 -0
- package/Server/API/DashboardAPI.ts +176 -492
- package/Server/API/DataSourceAPI.ts +268 -0
- package/Server/API/StatusPageAPI.ts +11 -1
- package/Server/API/UserAPI.ts +119 -0
- package/Server/Infrastructure/ClickhouseConfig.ts +59 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.ts +39 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.ts +24 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.ts +76 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Infrastructure/Queue.ts +26 -0
- package/Server/Infrastructure/QueueWorker.ts +17 -0
- package/Server/Middleware/TelemetryIngest.ts +8 -3
- package/Server/Services/AIInsightService.ts +132 -12
- package/Server/Services/AIRunService.ts +34 -0
- package/Server/Services/AIService.ts +17 -2
- package/Server/Services/AlertService.ts +38 -32
- package/Server/Services/AnalyticsDatabaseService.ts +8 -4
- package/Server/Services/DataSourceService.ts +200 -0
- package/Server/Services/HostService.ts +92 -0
- package/Server/Services/IncidentService.ts +45 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/MonitorService.ts +49 -0
- package/Server/Services/MonitorStatusService.ts +166 -0
- package/Server/Services/OpenTelemetryIngestService.ts +255 -184
- package/Server/Services/RumSessionPinService.ts +7 -21
- package/Server/Services/StatusPageSubscriberService.ts +13 -0
- package/Server/Services/UserService.ts +280 -9
- package/Server/Static/Vendor/README.md +62 -0
- package/Server/Static/Vendor/fonts/InterVariable.woff2 +0 -0
- package/Server/Static/Vendor/highlight/highlight.min.js +1244 -0
- package/Server/Static/Vendor/highlight/languages/apache.min.js +15 -0
- package/Server/Static/Vendor/highlight/languages/bash.min.js +21 -0
- package/Server/Static/Vendor/highlight/languages/c.min.js +41 -0
- package/Server/Static/Vendor/highlight/languages/cpp.min.js +47 -0
- package/Server/Static/Vendor/highlight/languages/csharp.min.js +49 -0
- package/Server/Static/Vendor/highlight/languages/css.min.js +31 -0
- package/Server/Static/Vendor/highlight/languages/diff.min.js +9 -0
- package/Server/Static/Vendor/highlight/languages/dns.min.js +11 -0
- package/Server/Static/Vendor/highlight/languages/dockerfile.min.js +8 -0
- package/Server/Static/Vendor/highlight/languages/go.min.js +20 -0
- package/Server/Static/Vendor/highlight/languages/graphql.min.js +12 -0
- package/Server/Static/Vendor/highlight/languages/http.min.js +14 -0
- package/Server/Static/Vendor/highlight/languages/ini.min.js +15 -0
- package/Server/Static/Vendor/highlight/languages/java.min.js +38 -0
- package/Server/Static/Vendor/highlight/languages/javascript.min.js +81 -0
- package/Server/Static/Vendor/highlight/languages/json.min.js +8 -0
- package/Server/Static/Vendor/highlight/languages/kotlin.min.js +46 -0
- package/Server/Static/Vendor/highlight/languages/lua.min.js +15 -0
- package/Server/Static/Vendor/highlight/languages/makefile.min.js +14 -0
- package/Server/Static/Vendor/highlight/languages/nginx.min.js +21 -0
- package/Server/Static/Vendor/highlight/languages/perl.min.js +41 -0
- package/Server/Static/Vendor/highlight/languages/php.min.js +59 -0
- package/Server/Static/Vendor/highlight/languages/powershell.min.js +39 -0
- package/Server/Static/Vendor/highlight/languages/python.min.js +42 -0
- package/Server/Static/Vendor/highlight/languages/r.min.js +26 -0
- package/Server/Static/Vendor/highlight/languages/ruby.min.js +54 -0
- package/Server/Static/Vendor/highlight/languages/rust.min.js +27 -0
- package/Server/Static/Vendor/highlight/languages/scala.min.js +28 -0
- package/Server/Static/Vendor/highlight/languages/sql.min.js +21 -0
- package/Server/Static/Vendor/highlight/languages/swift.min.js +68 -0
- package/Server/Static/Vendor/highlight/languages/typescript.min.js +99 -0
- package/Server/Static/Vendor/highlight/languages/xml.min.js +29 -0
- package/Server/Static/Vendor/highlight/languages/yaml.min.js +28 -0
- package/Server/Static/Vendor/highlight/styles/github-dark.min.css +10 -0
- package/Server/Static/Vendor/highlight/styles/vs2015.min.css +1 -0
- package/Server/Static/Vendor/tailwind/tailwind-3.4.5.js +21028 -0
- package/Server/Types/Database/Permissions/BasePermission.ts +7 -0
- package/Server/Types/Database/Permissions/DeletePermission.ts +2 -0
- package/Server/Types/Database/Permissions/ReadPermission.ts +3 -0
- package/Server/Types/Database/Permissions/TenantPermission.ts +101 -16
- package/Server/Utils/AI/CodeFix/FixRunBudget.ts +2 -2
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +90 -11
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +1 -0
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +1 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.ts +125 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +25 -15
- package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +256 -57
- package/Server/Utils/AI/SRE/Insights/InsightStore.ts +76 -18
- package/Server/Utils/AI/SRE/InvestigationTldr.ts +352 -0
- package/Server/Utils/AnalyticsDatabase/InsertDedupContext.ts +7 -2
- package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +1793 -0
- package/Server/Utils/Dashboard/PublicDashboardViewConfig.ts +65 -0
- package/Server/Utils/DataSource/ConnectorRegistry.ts +53 -0
- package/Server/Utils/DataSource/Connectors/ClickHouseConnector.ts +338 -0
- package/Server/Utils/DataSource/Connectors/ElasticsearchConnector.ts +717 -0
- package/Server/Utils/DataSource/Connectors/LokiConnector.ts +606 -0
- package/Server/Utils/DataSource/Connectors/MySqlConnector.ts +307 -0
- package/Server/Utils/DataSource/Connectors/PostgresConnector.ts +260 -0
- package/Server/Utils/DataSource/Connectors/PrometheusConnector.ts +555 -0
- package/Server/Utils/DataSource/Connectors/RestApiConnector.ts +597 -0
- package/Server/Utils/DataSource/Connectors/SqlServerConnector.ts +318 -0
- package/Server/Utils/DataSource/EgressGuard.ts +446 -0
- package/Server/Utils/DataSource/HttpFetch.ts +221 -0
- package/Server/Utils/DataSource/SqlQueryGuard.ts +383 -0
- package/Server/Utils/DataSource/SqlResultShaper.ts +372 -0
- package/Server/Utils/DataSource/Types.ts +93 -0
- package/Server/Utils/Database/PostgresErrorTranslator.ts +172 -17
- package/Server/Utils/InProcessMemo.ts +141 -0
- package/Server/Utils/InstanceHealth/TelemetryIngestion.ts +628 -0
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +58 -0
- package/Server/Utils/Monitor/MonitorResource.ts +14 -0
- package/Server/Utils/Response.ts +12 -1
- package/Server/Utils/SSRFProtection.ts +237 -0
- package/Server/Utils/StartServer.ts +8 -0
- package/Server/Utils/StatusPageSubscriberWebhook.ts +30 -0
- package/Server/Utils/Telemetry/CaptureSpan.ts +30 -18
- package/Server/Utils/Telemetry/IngestionTimestamp.ts +75 -0
- package/Server/Utils/Telemetry/ResourceHeartbeat.ts +99 -7
- package/Server/Utils/Telemetry/Telemetry.ts +112 -1
- package/Server/Utils/Telemetry.ts +104 -3
- package/Server/Utils/VendorAssets.ts +165 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +28 -5
- package/Server/Utils/Workspace/Slack/Slack.ts +5 -0
- package/Server/Views/Partials/Head.ejs +21 -7
- package/Tests/App/AdminDashboard/AdminProjectsIdFilter.test.tsx +207 -0
- package/Tests/App/AdminDashboard/AdminUsersIdFilter.test.tsx +216 -0
- package/Tests/App/Dashboard/AIInsightViewActions.test.tsx +422 -0
- package/Tests/App/Dashboard/AddWidgetModal.test.tsx +10 -3
- package/Tests/App/Dashboard/AlertsSideMenu.test.tsx +387 -0
- package/Tests/App/Dashboard/ChatActivityFeed.test.tsx +199 -0
- package/Tests/App/Dashboard/DataSourceChartSyntheticConfig.test.tsx +736 -0
- package/Tests/App/Dashboard/DataSourceQueryEditor.test.tsx +868 -0
- package/Tests/App/Dashboard/DataSourceWidgetCatalog.test.ts +440 -0
- package/Tests/App/Dashboard/DataSourceWidgetFetching.test.tsx +2109 -0
- package/Tests/App/Dashboard/DataSourceWidgetViews.test.tsx +726 -0
- package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +447 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +514 -3
- package/Tests/App/Dashboard/ProductMenuBreadcrumbs.test.tsx +391 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceSideMenu.test.tsx +326 -0
- package/Tests/App/Dashboard/SideMenuHarness.tsx +187 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +6 -1
- package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +1858 -0
- package/Tests/Models/DatabaseModels/DataSourceModelSecrets.test.ts +70 -0
- package/Tests/Server/API/AIInvestigationAPI.test.ts +187 -0
- package/Tests/Server/API/DashboardPublicDataSourceStrip.test.ts +686 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +585 -823
- package/Tests/Server/API/DataSourceAPIRoutes.test.ts +486 -0
- package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +291 -0
- package/Tests/Server/API/UserAuthenticationAPI.test.ts +641 -0
- package/Tests/Server/Infrastructure/ClickhouseKeepAliveOptions.test.ts +441 -0
- package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +140 -0
- package/Tests/Server/Services/AIInsightService.test.ts +266 -11
- package/Tests/Server/Services/AIRunAnalysisTldrPersistence.test.ts +160 -0
- package/Tests/Server/Services/AIServiceDailyBudget.test.ts +4 -0
- package/Tests/Server/Services/AlertMetricResourceAttributes.test.ts +352 -0
- package/Tests/Server/Services/DataSourceServiceSettings.test.ts +244 -0
- package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +397 -0
- package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +41 -2
- package/Tests/Server/Services/IncidentMetricResourceAttributes.test.ts +408 -0
- package/Tests/Server/Services/MonitorStatusServiceDeleteReferenceCleanup.test.ts +351 -0
- package/Tests/Server/Services/MonitorStatusServiceValidation.test.ts +171 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +398 -0
- package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +19 -0
- package/Tests/Server/Services/ProjectCallSMSConfigCredentialUniqueness.test.ts +305 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +36 -1
- package/Tests/Server/Services/RumSessionPinUniqueViolationRecovery.test.ts +163 -0
- package/Tests/Server/Services/UserAuthenticationService.test.ts +973 -0
- package/Tests/Server/Types/Database/ObjectIdColumnQuery.test.ts +262 -0
- package/Tests/Server/Types/Database/Permissions/TenantPermission.test.ts +358 -0
- package/Tests/Server/Utils/AI/FixRunBudget.test.ts +2 -2
- package/Tests/Server/Utils/AI/Insights/ExceptionSpikeDetector.test.ts +6 -1
- package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +121 -4
- package/Tests/Server/Utils/AI/Insights/NewExceptionDetector.test.ts +361 -10
- package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +292 -0
- package/Tests/Server/Utils/AI/InvestigationTldr.test.ts +623 -0
- package/Tests/Server/Utils/AI/InvestigationTldrWiring.test.ts +98 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +857 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardViewConfig.test.ts +480 -0
- package/Tests/Server/Utils/DataSource/ClickHouseConnector.test.ts +759 -0
- package/Tests/Server/Utils/DataSource/ConnectorRegistry.test.ts +37 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +645 -0
- package/Tests/Server/Utils/DataSource/ElasticsearchConnector.test.ts +1206 -0
- package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +616 -0
- package/Tests/Server/Utils/DataSource/LokiConnector.test.ts +970 -0
- package/Tests/Server/Utils/DataSource/MySqlConnector.test.ts +935 -0
- package/Tests/Server/Utils/DataSource/PostgresConnector.test.ts +854 -0
- package/Tests/Server/Utils/DataSource/PrometheusConnector.test.ts +881 -0
- package/Tests/Server/Utils/DataSource/RestApiConnector.test.ts +1020 -0
- package/Tests/Server/Utils/DataSource/SqlQueryGuard.test.ts +425 -0
- package/Tests/Server/Utils/DataSource/SqlResultShaper.test.ts +555 -0
- package/Tests/Server/Utils/DataSource/SqlServerConnector.test.ts +934 -0
- package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +228 -7
- package/Tests/Server/Utils/InProcessMemo.test.ts +292 -0
- package/Tests/Server/Utils/InstanceHealth/TelemetryIngestion.test.ts +960 -0
- package/Tests/Server/Utils/MicrosoftTeamsWebhookUrlValidation.test.ts +103 -0
- package/Tests/Server/Utils/Monitor/MonitorMetricResourceAttributes.test.ts +336 -0
- package/Tests/Server/Utils/OfflineAssetHygiene.test.ts +521 -0
- package/Tests/Server/Utils/ResponseRenderAnalytics.test.ts +143 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +193 -0
- package/Tests/Server/Utils/StatusPageSubscriberWebhook.test.ts +101 -0
- package/Tests/Server/Utils/TailwindBuildCopy.test.ts +225 -0
- package/Tests/Server/Utils/Telemetry/ResourceHeartbeatL1Memo.test.ts +355 -0
- package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +128 -0
- package/Tests/Server/Utils/Telemetry/TelemetryUtilAttributeKeys.test.ts +381 -0
- package/Tests/Server/Utils/Telemetry.test.ts +87 -0
- package/Tests/Server/Utils/VendorAssetIntegrity.test.ts +343 -0
- package/Tests/Server/Utils/VendorAssets.test.ts +671 -0
- package/Tests/Server/Views/OfflineRender.test.ts +297 -0
- package/Tests/Types/Dashboard/DataSourceComponentTypes.test.ts +618 -0
- package/Tests/Types/DateClickhouseFormat.test.ts +192 -0
- package/Tests/Types/Password.test.ts +363 -0
- package/Tests/UI/Components/ConfirmModal.test.tsx +7 -0
- package/Tests/UI/Components/ErrorBoundary.test.tsx +53 -0
- package/Tests/UI/Components/Modal.test.tsx +281 -1
- package/Tests/UI/Components/ObjectIdFilterPipeline.test.tsx +396 -0
- package/Tests/UI/Components/StatusPage/ResourceGroupNavigator.test.tsx +1147 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +116 -1
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
- package/Tests/Utils/Analytics.test.ts +23 -0
- package/Tests/Utils/Dashboard/Components/DashboardDataSourceComponents.test.ts +640 -0
- package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +138 -0
- package/Tests/Utils/DataSource/DataSourceValueReducer.test.ts +526 -0
- package/Tests/Utils/Metrics/MetricResourceAttributeUtil.test.ts +691 -0
- package/Tests/Utils/StatusPage/GroupHierarchyView.test.ts +1452 -0
- package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +931 -0
- package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +288 -0
- package/Tests/Utils/Telemetry/IngestionTimestamp.test.ts +170 -0
- package/Types/AI/AIInsightEvidence.ts +6 -0
- package/Types/Analytics/RevenueEvent.ts +31 -0
- package/Types/Dashboard/DashboardComponentType.ts +31 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.ts +27 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.ts +32 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.ts +30 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.ts +55 -0
- package/Types/DataSource/DataSourceLimits.ts +62 -0
- package/Types/DataSource/DataSourceQueryConfig.ts +41 -0
- package/Types/DataSource/DataSourceTableResult.ts +38 -0
- package/Types/DataSource/DataSourceType.ts +213 -0
- package/Types/Date.ts +43 -3
- package/Types/Password.ts +64 -0
- package/Types/Permission.ts +46 -0
- package/Types/UserAuthenticationStatus.ts +34 -0
- package/UI/Components/Button/Button.tsx +1 -1
- package/UI/Components/ErrorBoundary.tsx +459 -108
- package/UI/Components/Icon/Icon.tsx +10 -9
- package/UI/Components/Modal/ConfirmModal.tsx +6 -1
- package/UI/Components/Modal/Modal.tsx +267 -35
- package/UI/Components/Modal/ModalFooter.tsx +6 -1
- package/UI/Components/MoreMenu/MoreMenu.tsx +19 -4
- package/UI/Components/MoreMenu/MoreMenuItem.tsx +6 -1
- package/UI/Components/StatusPage/ResourceGrid.tsx +314 -0
- package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +808 -0
- package/UI/Components/StatusPage/ResourceList.tsx +570 -0
- package/UI/Styles/Theme.css +18 -0
- package/UI/Utils/API/RequestOptions.ts +7 -0
- package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +1 -0
- package/UI/Utils/ModelAPI/ModelAPI.ts +1 -0
- package/UI/Utils/TestDataSource.ts +61 -0
- package/UI/esbuild-config.js +45 -0
- package/Utils/Analytics.ts +15 -0
- package/Utils/Dashboard/Components/DashboardDataSourceChartComponent.ts +88 -0
- package/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.ts +123 -0
- package/Utils/Dashboard/Components/DashboardDataSourceShared.ts +16 -0
- package/Utils/Dashboard/Components/DashboardDataSourceTableComponent.ts +72 -0
- package/Utils/Dashboard/Components/DashboardDataSourceValueComponent.ts +126 -0
- package/Utils/Dashboard/Components/Index.ts +28 -0
- package/Utils/DataSource/DataSourceQueryText.ts +94 -0
- package/Utils/DataSource/DataSourceValueReducer.ts +156 -0
- package/Utils/Metrics/MetricResourceAttributeUtil.ts +380 -0
- package/Utils/NetworkDiscovery/ScanTargetUtil.ts +8 -6
- package/Utils/StatusPage/GroupHierarchyView.ts +931 -0
- package/Utils/StatusPage/ResourceExplorer.ts +853 -0
- package/build/dist/Models/DatabaseModels/AIRun.js +34 -0
- package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DataSource.js +774 -0
- package/build/dist/Models/DatabaseModels/DataSource.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js +14 -4
- package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +2 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js +2 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +2 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserSession.js +2 -0
- package/build/dist/Models/DatabaseModels/UserSession.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserTotpAuth.js +6 -4
- package/build/dist/Models/DatabaseModels/UserTotpAuth.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWebAuthn.js +5 -3
- package/build/dist/Models/DatabaseModels/UserWebAuthn.js.map +1 -1
- package/build/dist/Server/API/AIInsightAPI.js +34 -4
- package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +23 -0
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +119 -433
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/DataSourceAPI.js +173 -0
- package/build/dist/Server/API/DataSourceAPI.js.map +1 -0
- package/build/dist/Server/API/StatusPageAPI.js +11 -1
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/UserAPI.js +94 -2
- package/build/dist/Server/API/UserAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js +49 -0
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js +64 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Queue.js +27 -0
- package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +13 -0
- package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +8 -3
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AIInsightService.js +110 -10
- package/build/dist/Server/Services/AIInsightService.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +34 -0
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +16 -2
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +28 -35
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +8 -4
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DataSourceService.js +159 -0
- package/build/dist/Server/Services/DataSourceService.js.map +1 -0
- package/build/dist/Server/Services/HostService.js +74 -0
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +35 -24
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +45 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusService.js +129 -0
- package/build/dist/Server/Services/MonitorStatusService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +222 -159
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionPinService.js +7 -15
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +10 -0
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +241 -10
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js +6 -0
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/DeletePermission.js +1 -0
- package/build/dist/Server/Types/Database/Permissions/DeletePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +2 -0
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +68 -12
- package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +2 -2
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +68 -8
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +1 -0
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +1 -0
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js +97 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +17 -15
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +178 -54
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js +65 -16
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js +303 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js.map +1 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js.map +1 -1
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +1261 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js +47 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js +42 -0
- package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js +187 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js +493 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js +399 -0
- package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js +195 -0
- package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js +149 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js +362 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js +342 -0
- package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js +186 -0
- package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +305 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/HttpFetch.js +134 -0
- package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js +331 -0
- package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/SqlResultShaper.js +280 -0
- package/build/dist/Server/Utils/DataSource/SqlResultShaper.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Types.js +2 -0
- package/build/dist/Server/Utils/DataSource/Types.js.map +1 -0
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +103 -9
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -1
- package/build/dist/Server/Utils/InProcessMemo.js +113 -0
- package/build/dist/Server/Utils/InProcessMemo.js.map +1 -0
- package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js +406 -0
- package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +34 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +14 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Response.js +9 -1
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +192 -0
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -0
- package/build/dist/Server/Utils/StartServer.js +7 -0
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js +24 -0
- package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +25 -11
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js +32 -0
- package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +92 -5
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +92 -6
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry.js +93 -6
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/VendorAssets.js +121 -0
- package/build/dist/Server/Utils/VendorAssets.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +25 -4
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +5 -0
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Types/Analytics/RevenueEvent.js +26 -0
- package/build/dist/Types/Analytics/RevenueEvent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js +27 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js +16 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceLimits.js +47 -0
- package/build/dist/Types/DataSource/DataSourceLimits.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceQueryConfig.js +10 -0
- package/build/dist/Types/DataSource/DataSourceQueryConfig.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceTableResult.js +14 -0
- package/build/dist/Types/DataSource/DataSourceTableResult.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceType.js +183 -0
- package/build/dist/Types/DataSource/DataSourceType.js.map +1 -0
- package/build/dist/Types/Date.js +38 -3
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Password.js +56 -0
- package/build/dist/Types/Password.js.map +1 -0
- package/build/dist/Types/Permission.js +42 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/UserAuthenticationStatus.js +2 -0
- package/build/dist/Types/UserAuthenticationStatus.js.map +1 -0
- package/build/dist/UI/Components/ErrorBoundary.js +388 -72
- package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +10 -4
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +178 -19
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js +3 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +9 -6
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +7 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js +119 -0
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +354 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -0
- package/build/dist/UI/Components/StatusPage/ResourceList.js +203 -0
- package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -0
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +1 -6
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +3 -8
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/TestDataSource.js +39 -0
- package/build/dist/UI/Utils/TestDataSource.js.map +1 -0
- package/build/dist/Utils/Analytics.js +4 -0
- package/build/dist/Utils/Analytics.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js +79 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js +111 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js +15 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js +62 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js +112 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +16 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/DataSource/DataSourceQueryText.js +64 -0
- package/build/dist/Utils/DataSource/DataSourceQueryText.js.map +1 -0
- package/build/dist/Utils/DataSource/DataSourceValueReducer.js +124 -0
- package/build/dist/Utils/DataSource/DataSourceValueReducer.js.map +1 -0
- package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js +281 -0
- package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +8 -6
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -1
- package/build/dist/Utils/StatusPage/GroupHierarchyView.js +560 -0
- package/build/dist/Utils/StatusPage/GroupHierarchyView.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js +519 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -0
- package/jest.config.json +1 -0
- package/package.json +5 -1
- package/tsconfig.json +12 -10
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import QueryPermission from "../../../../Server/Types/Database/Permissions/QueryPermission";
|
|
2
|
+
import QueryUtil from "../../../../Server/Types/Database/QueryUtil";
|
|
3
|
+
import Project from "../../../../Models/DatabaseModels/Project";
|
|
4
|
+
import User from "../../../../Models/DatabaseModels/User";
|
|
5
|
+
import DatabaseCommonInteractionProps from "../../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
6
|
+
import EqualTo from "../../../../Types/BaseDatabase/EqualTo";
|
|
7
|
+
import NotEqual from "../../../../Types/BaseDatabase/NotEqual";
|
|
8
|
+
import Search from "../../../../Types/BaseDatabase/Search";
|
|
9
|
+
import StartsWith from "../../../../Types/BaseDatabase/StartsWith";
|
|
10
|
+
import ObjectID from "../../../../Types/ObjectID";
|
|
11
|
+
import { DatabaseBaseModelType } from "../../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
12
|
+
import { FindOperator } from "typeorm";
|
|
13
|
+
import { describe, expect, it } from "@jest/globals";
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* The server half of "filter users and projects by ID" in the admin
|
|
17
|
+
* dashboard.
|
|
18
|
+
*
|
|
19
|
+
* `_id` is not an ordinary text column - it is a Postgres `uuid`, and uuid has
|
|
20
|
+
* no ILIKE. A partial-match filter on it only works because QueryHelper.search
|
|
21
|
+
* wraps the column in `CAST(... AS TEXT)` first; emit the ILIKE against the
|
|
22
|
+
* raw column and Postgres rejects the whole statement with
|
|
23
|
+
* `operator does not exist: uuid ~~* unknown`. That cast is invisible from the
|
|
24
|
+
* UI - the filter looks identical either way and simply errors at fetch time -
|
|
25
|
+
* so it is asserted here rather than inferred.
|
|
26
|
+
*
|
|
27
|
+
* The other half is the permission layer: every queried column is checked
|
|
28
|
+
* against what the caller may read, and a column it does not recognise is
|
|
29
|
+
* rejected outright. `_id` passes as an always-readable column, which is what
|
|
30
|
+
* lets the filter reach the database at all.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
const A_UUID: string = "5f0e8e3a-1f24-4a2f-9e4c-2b1d3c4e5f60";
|
|
34
|
+
|
|
35
|
+
type SerializeFunction = (
|
|
36
|
+
modelType: DatabaseBaseModelType,
|
|
37
|
+
query: Record<string, unknown>,
|
|
38
|
+
) => Record<string, any>;
|
|
39
|
+
|
|
40
|
+
const serialize: SerializeFunction = (
|
|
41
|
+
modelType: DatabaseBaseModelType,
|
|
42
|
+
query: Record<string, unknown>,
|
|
43
|
+
): Record<string, any> => {
|
|
44
|
+
return QueryUtil.serializeQuery(modelType, query as any) as unknown as Record<
|
|
45
|
+
string,
|
|
46
|
+
any
|
|
47
|
+
>;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
type RawSqlFunction = (operator: unknown, aliasPath: string) => string;
|
|
51
|
+
|
|
52
|
+
const rawSql: RawSqlFunction = (
|
|
53
|
+
operator: unknown,
|
|
54
|
+
aliasPath: string,
|
|
55
|
+
): string => {
|
|
56
|
+
const getSql: ((aliasPath: string) => string) | undefined = (
|
|
57
|
+
operator as FindOperator<unknown>
|
|
58
|
+
).getSql;
|
|
59
|
+
|
|
60
|
+
if (!getSql) {
|
|
61
|
+
throw new Error("Expected a Raw FindOperator with a SQL generator.");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return getSql(aliasPath);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
type ParamsFunction = (operator: unknown) => Array<unknown>;
|
|
68
|
+
|
|
69
|
+
const params: ParamsFunction = (operator: unknown): Array<unknown> => {
|
|
70
|
+
return Object.values(
|
|
71
|
+
(
|
|
72
|
+
operator as unknown as {
|
|
73
|
+
objectLiteralParameters: Record<string, unknown>;
|
|
74
|
+
}
|
|
75
|
+
).objectLiteralParameters,
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
describe("QueryUtil.serializeQuery — filtering on the _id column", () => {
|
|
80
|
+
describe("User", () => {
|
|
81
|
+
/*
|
|
82
|
+
* The default operator in the ID filter. A Search that reached TypeORM
|
|
83
|
+
* un-serialized would silently degrade into an exact equality, so pasting
|
|
84
|
+
* a fragment of an id would quietly match nothing at all.
|
|
85
|
+
*/
|
|
86
|
+
it("turns a partial-id Search into an ILIKE over the id cast to text", () => {
|
|
87
|
+
const result: Record<string, any> = serialize(User, {
|
|
88
|
+
_id: new Search("5f0e8e3a"),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
expect(result["_id"]).toBeInstanceOf(FindOperator);
|
|
92
|
+
expect(result["_id"]).not.toBeInstanceOf(Search);
|
|
93
|
+
expect(result["_id"].type).toBe("raw");
|
|
94
|
+
|
|
95
|
+
const sql: string = rawSql(result["_id"], "User._id");
|
|
96
|
+
|
|
97
|
+
// Without the cast this is invalid SQL against a uuid column.
|
|
98
|
+
expect(sql).toContain("CAST(User._id AS TEXT)");
|
|
99
|
+
expect(sql).toContain("ILIKE");
|
|
100
|
+
expect(params(result["_id"])).toEqual(["%5f0e8e3a%"]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("turns a whole-id EqualTo into a plain equality", () => {
|
|
104
|
+
const result: Record<string, any> = serialize(User, {
|
|
105
|
+
_id: new EqualTo(A_UUID),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
expect(result["_id"].type).toBe("raw");
|
|
109
|
+
expect(rawSql(result["_id"], "User._id")).toContain("User._id = :");
|
|
110
|
+
expect(params(result["_id"])).toEqual([A_UUID]);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("turns a NotEqual into an inequality", () => {
|
|
114
|
+
const result: Record<string, any> = serialize(User, {
|
|
115
|
+
_id: new NotEqual(A_UUID),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(rawSql(result["_id"], "User._id")).toContain("User._id != :");
|
|
119
|
+
expect(params(result["_id"])).toEqual([A_UUID]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
/*
|
|
123
|
+
* Prefix matching is the operator an admin reaches for with a truncated
|
|
124
|
+
* id, so it needs the same cast as `contains` - and an anchored pattern,
|
|
125
|
+
* not a floating one.
|
|
126
|
+
*/
|
|
127
|
+
it("anchors a StartsWith to the front of the id", () => {
|
|
128
|
+
const result: Record<string, any> = serialize(User, {
|
|
129
|
+
_id: new StartsWith("5f0e8e3a"),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
expect(rawSql(result["_id"], "User._id")).toContain(
|
|
133
|
+
"CAST(User._id AS TEXT)",
|
|
134
|
+
);
|
|
135
|
+
expect(params(result["_id"])).toEqual(["5f0e8e3a%"]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
/*
|
|
139
|
+
* Ids are copied out of the UI with whatever case the source used, and
|
|
140
|
+
* ILIKE is case-insensitive anyway - but the bound parameter has to be
|
|
141
|
+
* lower-cased consistently or a mixed-case paste behaves differently from
|
|
142
|
+
* the same id typed in lower case.
|
|
143
|
+
*/
|
|
144
|
+
it("matches an id regardless of the case it was pasted in", () => {
|
|
145
|
+
expect(
|
|
146
|
+
params(
|
|
147
|
+
serialize(User, { _id: new Search(A_UUID.toUpperCase()) })["_id"],
|
|
148
|
+
),
|
|
149
|
+
).toEqual([`%${A_UUID}%`]);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("leaves a bare id string as a plain equality value", () => {
|
|
153
|
+
expect(serialize(User, { _id: A_UUID })["_id"]).toBe(A_UUID);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("unwraps an ObjectID into an equality on the id", () => {
|
|
157
|
+
const result: Record<string, any> = serialize(User, {
|
|
158
|
+
_id: new ObjectID(A_UUID),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
expect(result["_id"].type).toBe("raw");
|
|
162
|
+
expect(params(result["_id"])).toEqual([A_UUID]);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
/*
|
|
167
|
+
* Project is a different model with a different column set, and the admin
|
|
168
|
+
* dashboard filters it the same way. Nothing about the _id handling is
|
|
169
|
+
* per-model, and this is what says so.
|
|
170
|
+
*/
|
|
171
|
+
describe("Project", () => {
|
|
172
|
+
it("turns a partial-id Search into an ILIKE over the id cast to text", () => {
|
|
173
|
+
const result: Record<string, any> = serialize(Project, {
|
|
174
|
+
_id: new Search("5f0e8e3a"),
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
expect(result["_id"].type).toBe("raw");
|
|
178
|
+
expect(rawSql(result["_id"], "Project._id")).toContain(
|
|
179
|
+
"CAST(Project._id AS TEXT)",
|
|
180
|
+
);
|
|
181
|
+
expect(params(result["_id"])).toEqual(["%5f0e8e3a%"]);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("turns a whole-id EqualTo into a plain equality", () => {
|
|
185
|
+
const result: Record<string, any> = serialize(Project, {
|
|
186
|
+
_id: new EqualTo(A_UUID),
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
expect(rawSql(result["_id"], "Project._id")).toContain("Project._id = :");
|
|
190
|
+
expect(params(result["_id"])).toEqual([A_UUID]);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
/*
|
|
196
|
+
* `checkQueryPermission` walks every key of the incoming query and rejects
|
|
197
|
+
* anything the caller cannot read. An id filter arrives as a query key like
|
|
198
|
+
* any other, so it has to survive that walk.
|
|
199
|
+
*/
|
|
200
|
+
describe("QueryPermission.checkQueryPermission — querying by _id", () => {
|
|
201
|
+
/*
|
|
202
|
+
* No permissions at all: the weakest caller there is. `_id` is one of the
|
|
203
|
+
* always-readable columns, so even this caller may filter on it - which is
|
|
204
|
+
* what keeps the ID filter working for every table that offers one, without
|
|
205
|
+
* a per-model permission grant.
|
|
206
|
+
*/
|
|
207
|
+
const noPermissions: DatabaseCommonInteractionProps = {
|
|
208
|
+
userGlobalAccessPermission: {
|
|
209
|
+
projectIds: [],
|
|
210
|
+
globalPermissions: [],
|
|
211
|
+
_type: "UserGlobalAccessPermission",
|
|
212
|
+
},
|
|
213
|
+
} as unknown as DatabaseCommonInteractionProps;
|
|
214
|
+
|
|
215
|
+
it("allows filtering users by _id", () => {
|
|
216
|
+
expect(() => {
|
|
217
|
+
QueryPermission.checkQueryPermission<User>(
|
|
218
|
+
User,
|
|
219
|
+
{ _id: new Search("5f0e8e3a") } as any,
|
|
220
|
+
noPermissions,
|
|
221
|
+
);
|
|
222
|
+
}).not.toThrow();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("allows filtering projects by _id", () => {
|
|
226
|
+
expect(() => {
|
|
227
|
+
QueryPermission.checkQueryPermission<Project>(
|
|
228
|
+
Project,
|
|
229
|
+
{ _id: new Search("5f0e8e3a") } as any,
|
|
230
|
+
noPermissions,
|
|
231
|
+
);
|
|
232
|
+
}).not.toThrow();
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
/*
|
|
236
|
+
* The counter-case. Without it the two tests above would pass just as well
|
|
237
|
+
* against a permission check that waves everything through.
|
|
238
|
+
*/
|
|
239
|
+
it("still rejects a column that does not exist", () => {
|
|
240
|
+
expect(() => {
|
|
241
|
+
QueryPermission.checkQueryPermission<User>(
|
|
242
|
+
User,
|
|
243
|
+
{ notAColumn: new Search("x") } as any,
|
|
244
|
+
noPermissions,
|
|
245
|
+
);
|
|
246
|
+
}).toThrow(/Invalid column on User/);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
/*
|
|
250
|
+
* ...and a real column that this caller has no permission to read, which is
|
|
251
|
+
* the check `_id` is deliberately exempt from.
|
|
252
|
+
*/
|
|
253
|
+
it("still rejects a real column the caller cannot read", () => {
|
|
254
|
+
expect(() => {
|
|
255
|
+
QueryPermission.checkQueryPermission<User>(
|
|
256
|
+
User,
|
|
257
|
+
{ isMasterAdmin: true } as any,
|
|
258
|
+
noPermissions,
|
|
259
|
+
);
|
|
260
|
+
}).toThrow();
|
|
261
|
+
});
|
|
262
|
+
});
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import User from "../../../../../Models/DatabaseModels/User";
|
|
2
|
+
import UserOnCallLog from "../../../../../Models/DatabaseModels/UserOnCallLog";
|
|
3
|
+
import UserOnCallLogTimeline from "../../../../../Models/DatabaseModels/UserOnCallLogTimeline";
|
|
4
|
+
import UserSession from "../../../../../Models/DatabaseModels/UserSession";
|
|
5
|
+
import UserTotpAuth from "../../../../../Models/DatabaseModels/UserTotpAuth";
|
|
6
|
+
import UserWebAuthn from "../../../../../Models/DatabaseModels/UserWebAuthn";
|
|
7
|
+
import BaseModel from "../../../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
8
|
+
import UserService from "../../../../../Server/Services/UserService";
|
|
9
|
+
import DatabaseRequestType from "../../../../../Server/Types/BaseDatabase/DatabaseRequestType";
|
|
10
|
+
import DeleteBy from "../../../../../Server/Types/Database/DeleteBy";
|
|
11
|
+
import BasePermission from "../../../../../Server/Types/Database/Permissions/BasePermission";
|
|
12
|
+
import TenantPermission from "../../../../../Server/Types/Database/Permissions/TenantPermission";
|
|
13
|
+
import Query from "../../../../../Server/Types/Database/Query";
|
|
14
|
+
import UpdateBy from "../../../../../Server/Types/Database/UpdateBy";
|
|
15
|
+
import NotEqual from "../../../../../Types/BaseDatabase/NotEqual";
|
|
16
|
+
import DatabaseCommonInteractionProps from "../../../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
17
|
+
import ColumnAccessControl from "../../../../../Types/Database/AccessControl/ColumnAccessControl";
|
|
18
|
+
import TableAccessControl from "../../../../../Types/Database/AccessControl/TableAccessControl";
|
|
19
|
+
import CurrentUserCanAccessRecordBy from "../../../../../Types/Database/CurrentUserCanAccessRecordBy";
|
|
20
|
+
import TableColumn from "../../../../../Types/Database/TableColumn";
|
|
21
|
+
import TableColumnType from "../../../../../Types/Database/TableColumnType";
|
|
22
|
+
import TenantColumn from "../../../../../Types/Database/TenantColumn";
|
|
23
|
+
import NotAuthorizedException from "../../../../../Types/Exception/NotAuthorizedException";
|
|
24
|
+
import ObjectID from "../../../../../Types/ObjectID";
|
|
25
|
+
import Permission from "../../../../../Types/Permission";
|
|
26
|
+
import UserType from "../../../../../Types/UserType";
|
|
27
|
+
|
|
28
|
+
@TableAccessControl({
|
|
29
|
+
create: [Permission.CurrentUser],
|
|
30
|
+
read: [Permission.CurrentUser],
|
|
31
|
+
update: [Permission.CurrentUser],
|
|
32
|
+
delete: [Permission.CurrentUser],
|
|
33
|
+
})
|
|
34
|
+
@CurrentUserCanAccessRecordBy("userId")
|
|
35
|
+
class MisconfiguredCurrentUserModel extends BaseModel {}
|
|
36
|
+
|
|
37
|
+
@TableAccessControl({
|
|
38
|
+
create: [Permission.CurrentUser],
|
|
39
|
+
read: [Permission.CurrentUser],
|
|
40
|
+
update: [Permission.CurrentUser],
|
|
41
|
+
delete: [Permission.CurrentUser],
|
|
42
|
+
})
|
|
43
|
+
class MissingCurrentUserScopeModel extends BaseModel {}
|
|
44
|
+
|
|
45
|
+
@TableAccessControl({
|
|
46
|
+
create: [Permission.CurrentUser],
|
|
47
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
48
|
+
update: [Permission.CurrentUser],
|
|
49
|
+
delete: [Permission.CurrentUser],
|
|
50
|
+
})
|
|
51
|
+
@CurrentUserCanAccessRecordBy("userId")
|
|
52
|
+
@TenantColumn("projectId")
|
|
53
|
+
class TenantScopedCurrentUserModel extends BaseModel {
|
|
54
|
+
@ColumnAccessControl({
|
|
55
|
+
create: [],
|
|
56
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
57
|
+
update: [],
|
|
58
|
+
})
|
|
59
|
+
@TableColumn({
|
|
60
|
+
type: TableColumnType.ObjectID,
|
|
61
|
+
title: "Project ID",
|
|
62
|
+
})
|
|
63
|
+
public projectId?: ObjectID = undefined;
|
|
64
|
+
|
|
65
|
+
@ColumnAccessControl({
|
|
66
|
+
create: [],
|
|
67
|
+
read: [Permission.CurrentUser, Permission.ProjectAdmin],
|
|
68
|
+
update: [],
|
|
69
|
+
})
|
|
70
|
+
@TableColumn({
|
|
71
|
+
type: TableColumnType.ObjectID,
|
|
72
|
+
title: "User ID",
|
|
73
|
+
})
|
|
74
|
+
public userId?: ObjectID = undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
describe("TenantPermission current-user ownership scope", () => {
|
|
78
|
+
const userId: ObjectID = ObjectID.generate();
|
|
79
|
+
const victimUserId: ObjectID = ObjectID.generate();
|
|
80
|
+
|
|
81
|
+
function makeUserProps(): DatabaseCommonInteractionProps {
|
|
82
|
+
return {
|
|
83
|
+
userId,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
it.each([UserTotpAuth, UserWebAuthn, UserSession])(
|
|
88
|
+
"scopes %p queries to the authenticated user's records",
|
|
89
|
+
async (modelType: { new (): BaseModel }) => {
|
|
90
|
+
for (const requestType of [
|
|
91
|
+
DatabaseRequestType.Read,
|
|
92
|
+
DatabaseRequestType.Update,
|
|
93
|
+
DatabaseRequestType.Delete,
|
|
94
|
+
]) {
|
|
95
|
+
const query: Query<BaseModel> =
|
|
96
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
97
|
+
modelType,
|
|
98
|
+
{},
|
|
99
|
+
null,
|
|
100
|
+
makeUserProps(),
|
|
101
|
+
requestType,
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
expect((query as any).userId?.toString()).toBe(userId.toString());
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
it.each([UserTotpAuth, UserWebAuthn, UserSession])(
|
|
110
|
+
"rejects %p operations that explicitly target another user",
|
|
111
|
+
async (modelType: { new (): BaseModel }) => {
|
|
112
|
+
for (const requestType of [
|
|
113
|
+
DatabaseRequestType.Read,
|
|
114
|
+
DatabaseRequestType.Update,
|
|
115
|
+
DatabaseRequestType.Delete,
|
|
116
|
+
]) {
|
|
117
|
+
await expect(
|
|
118
|
+
TenantPermission.addTenantScopeToQuery(
|
|
119
|
+
modelType,
|
|
120
|
+
{ userId: victimUserId } as any,
|
|
121
|
+
null,
|
|
122
|
+
makeUserProps(),
|
|
123
|
+
requestType,
|
|
124
|
+
),
|
|
125
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
it("rejects CurrentUser access when a non-user caller has no user identity", async () => {
|
|
131
|
+
const apiKeyProps: DatabaseCommonInteractionProps = {
|
|
132
|
+
userType: UserType.API,
|
|
133
|
+
userGlobalAccessPermission: {
|
|
134
|
+
projectIds: [ObjectID.generate()],
|
|
135
|
+
globalPermissions: [
|
|
136
|
+
Permission.Public,
|
|
137
|
+
Permission.User,
|
|
138
|
+
Permission.CurrentUser,
|
|
139
|
+
],
|
|
140
|
+
_type: "UserGlobalAccessPermission",
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
await expect(
|
|
145
|
+
BasePermission.checkPermissions(
|
|
146
|
+
UserTotpAuth,
|
|
147
|
+
{},
|
|
148
|
+
null,
|
|
149
|
+
apiKeyProps,
|
|
150
|
+
DatabaseRequestType.Read,
|
|
151
|
+
),
|
|
152
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("fails closed when a CurrentUser model resolves no ownership filter", async () => {
|
|
156
|
+
await expect(
|
|
157
|
+
TenantPermission.addTenantScopeToQuery(
|
|
158
|
+
MisconfiguredCurrentUserModel,
|
|
159
|
+
{},
|
|
160
|
+
null,
|
|
161
|
+
makeUserProps(),
|
|
162
|
+
DatabaseRequestType.Read,
|
|
163
|
+
),
|
|
164
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("fails closed when CurrentUser ownership metadata is missing", async () => {
|
|
168
|
+
await expect(
|
|
169
|
+
TenantPermission.addTenantScopeToQuery(
|
|
170
|
+
MissingCurrentUserScopeModel,
|
|
171
|
+
{},
|
|
172
|
+
null,
|
|
173
|
+
makeUserProps(),
|
|
174
|
+
DatabaseRequestType.Read,
|
|
175
|
+
),
|
|
176
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("keeps User reads scoped to the authenticated user's primary key", async () => {
|
|
180
|
+
const query: Query<User> = await TenantPermission.addTenantScopeToQuery(
|
|
181
|
+
User,
|
|
182
|
+
{},
|
|
183
|
+
null,
|
|
184
|
+
makeUserProps(),
|
|
185
|
+
DatabaseRequestType.Read,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
expect((query as any)._id?.toString()).toBe(userId.toString());
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("rejects query operators that disguise a broad ownership filter", async () => {
|
|
192
|
+
await expect(
|
|
193
|
+
TenantPermission.addTenantScopeToQuery(
|
|
194
|
+
User,
|
|
195
|
+
{ _id: new NotEqual<string>(userId.toString()) },
|
|
196
|
+
null,
|
|
197
|
+
makeUserProps(),
|
|
198
|
+
DatabaseRequestType.Update,
|
|
199
|
+
),
|
|
200
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("rejects deleting another User instead of redirecting the delete", async () => {
|
|
204
|
+
await expect(
|
|
205
|
+
TenantPermission.addTenantScopeToQuery(
|
|
206
|
+
User,
|
|
207
|
+
{ _id: victimUserId },
|
|
208
|
+
null,
|
|
209
|
+
makeUserProps(),
|
|
210
|
+
DatabaseRequestType.Delete,
|
|
211
|
+
),
|
|
212
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("allows deleting the authenticated User's own record", async () => {
|
|
216
|
+
const deleteQuery: Query<User> =
|
|
217
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
218
|
+
User,
|
|
219
|
+
{ _id: userId },
|
|
220
|
+
null,
|
|
221
|
+
makeUserProps(),
|
|
222
|
+
DatabaseRequestType.Delete,
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
expect((deleteQuery as any)._id?.toString()).toBe(userId.toString());
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it.each([UserOnCallLog, UserOnCallLogTimeline])(
|
|
229
|
+
"scopes %p reads to the current user within the tenant",
|
|
230
|
+
async (modelType: { new (): BaseModel }) => {
|
|
231
|
+
const projectId: ObjectID = ObjectID.generate();
|
|
232
|
+
const query: Query<BaseModel> =
|
|
233
|
+
await TenantPermission.addTenantScopeToQuery(
|
|
234
|
+
modelType,
|
|
235
|
+
{},
|
|
236
|
+
null,
|
|
237
|
+
{ ...makeUserProps(), tenantId: projectId },
|
|
238
|
+
DatabaseRequestType.Read,
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
expect((query as any).projectId?.toString()).toBe(projectId.toString());
|
|
242
|
+
expect((query as any).userId?.toString()).toBe(userId.toString());
|
|
243
|
+
},
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
it("does not mutate a query reused for list and count permission checks", async () => {
|
|
247
|
+
const reusedQuery: Query<UserTotpAuth> = {};
|
|
248
|
+
|
|
249
|
+
await BasePermission.checkPermissions(
|
|
250
|
+
UserTotpAuth,
|
|
251
|
+
reusedQuery,
|
|
252
|
+
null,
|
|
253
|
+
makeUserProps(),
|
|
254
|
+
DatabaseRequestType.Read,
|
|
255
|
+
);
|
|
256
|
+
await expect(
|
|
257
|
+
BasePermission.checkPermissions(
|
|
258
|
+
UserTotpAuth,
|
|
259
|
+
reusedQuery,
|
|
260
|
+
null,
|
|
261
|
+
makeUserProps(),
|
|
262
|
+
DatabaseRequestType.Read,
|
|
263
|
+
),
|
|
264
|
+
).resolves.toBeDefined();
|
|
265
|
+
|
|
266
|
+
expect(reusedQuery).toEqual({});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("isolates CurrentUser scope for every project in a multi-tenant query", async () => {
|
|
270
|
+
const currentUserProjectId: ObjectID = ObjectID.generate();
|
|
271
|
+
const adminProjectId: ObjectID = ObjectID.generate();
|
|
272
|
+
|
|
273
|
+
for (const projectIds of [
|
|
274
|
+
[currentUserProjectId, adminProjectId],
|
|
275
|
+
[adminProjectId, currentUserProjectId],
|
|
276
|
+
]) {
|
|
277
|
+
const queries: Array<Record<string, unknown>> =
|
|
278
|
+
(await TenantPermission.addTenantScopeToQuery(
|
|
279
|
+
TenantScopedCurrentUserModel,
|
|
280
|
+
{},
|
|
281
|
+
null,
|
|
282
|
+
{
|
|
283
|
+
userId,
|
|
284
|
+
userGlobalAccessPermission: {
|
|
285
|
+
projectIds,
|
|
286
|
+
globalPermissions: [Permission.Public, Permission.CurrentUser],
|
|
287
|
+
_type: "UserGlobalAccessPermission",
|
|
288
|
+
},
|
|
289
|
+
userTenantAccessPermission: {
|
|
290
|
+
[adminProjectId.toString()]: {
|
|
291
|
+
projectId: adminProjectId,
|
|
292
|
+
permissions: [
|
|
293
|
+
{
|
|
294
|
+
permission: Permission.ProjectAdmin,
|
|
295
|
+
labelIds: [],
|
|
296
|
+
isBlockPermission: false,
|
|
297
|
+
_type: "UserPermission",
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
_type: "UserTenantAccessPermission",
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
DatabaseRequestType.Read,
|
|
305
|
+
)) as unknown as Array<Record<string, unknown>>;
|
|
306
|
+
|
|
307
|
+
expect(queries).toHaveLength(2);
|
|
308
|
+
expect(
|
|
309
|
+
queries[projectIds.indexOf(currentUserProjectId)]?.["userId"],
|
|
310
|
+
).toBeDefined();
|
|
311
|
+
expect(
|
|
312
|
+
queries[projectIds.indexOf(adminProjectId)]?.["userId"],
|
|
313
|
+
).toBeUndefined();
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it("rejects a cross-user delete before UserService inspects memberships", async () => {
|
|
318
|
+
await expect(
|
|
319
|
+
(UserService as any).onBeforeDelete({
|
|
320
|
+
query: { _id: victimUserId },
|
|
321
|
+
props: makeUserProps(),
|
|
322
|
+
limit: 1,
|
|
323
|
+
skip: 0,
|
|
324
|
+
} as DeleteBy<User>),
|
|
325
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it("rejects broad update operators before UserService runs user hooks", async () => {
|
|
329
|
+
await expect(
|
|
330
|
+
(UserService as any).onBeforeUpdate({
|
|
331
|
+
query: { _id: new NotEqual<string>(userId.toString()) },
|
|
332
|
+
data: { password: "new-password" },
|
|
333
|
+
props: makeUserProps(),
|
|
334
|
+
limit: 1,
|
|
335
|
+
skip: 0,
|
|
336
|
+
} as unknown as UpdateBy<User>),
|
|
337
|
+
).rejects.toThrow(NotAuthorizedException);
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
describe("two-factor credential ownership columns", () => {
|
|
342
|
+
it("prevents TOTP ownership and verification from being changed via CRUD", () => {
|
|
343
|
+
const model: UserTotpAuth = new UserTotpAuth();
|
|
344
|
+
|
|
345
|
+
expect(model.getColumnAccessControlFor("user")?.update).toEqual([]);
|
|
346
|
+
expect(model.getColumnAccessControlFor("user")?.create).toEqual([]);
|
|
347
|
+
expect(model.getColumnAccessControlFor("userId")?.update).toEqual([]);
|
|
348
|
+
expect(model.getColumnAccessControlFor("isVerified")?.update).toEqual([]);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it("prevents WebAuthn ownership from being changed via CRUD", () => {
|
|
352
|
+
const model: UserWebAuthn = new UserWebAuthn();
|
|
353
|
+
|
|
354
|
+
expect(model.getColumnAccessControlFor("user")?.update).toEqual([]);
|
|
355
|
+
expect(model.getColumnAccessControlFor("user")?.create).toEqual([]);
|
|
356
|
+
expect(model.getColumnAccessControlFor("userId")?.update).toEqual([]);
|
|
357
|
+
});
|
|
358
|
+
});
|
|
@@ -100,7 +100,7 @@ describe("FixRunBudget.describeRejection", () => {
|
|
|
100
100
|
);
|
|
101
101
|
|
|
102
102
|
expect(message).toMatch(/Daily Incident AI Fix Task Limit/);
|
|
103
|
-
expect(message).toMatch(/Incidents >
|
|
103
|
+
expect(message).toMatch(/Incidents > AI > Investigation/);
|
|
104
104
|
expect(message).toMatch(/0/);
|
|
105
105
|
});
|
|
106
106
|
|
|
@@ -112,7 +112,7 @@ describe("FixRunBudget.describeRejection", () => {
|
|
|
112
112
|
|
|
113
113
|
expect(message).toMatch(/10 of 10/);
|
|
114
114
|
expect(message).toMatch(/Daily Alert AI Fix Task Limit/);
|
|
115
|
-
expect(message).toMatch(/Alerts >
|
|
115
|
+
expect(message).toMatch(/Alerts > AI > Investigation/);
|
|
116
116
|
expect(message).toMatch(new RegExp(String(DEFAULT_DAILY_FIX_RUN_LIMIT)));
|
|
117
117
|
});
|
|
118
118
|
|
|
@@ -208,8 +208,13 @@ describe("ExceptionSpikeDetector.detect (IO wiring)", () => {
|
|
|
208
208
|
`exception-spike:${exceptionId.toString()}`,
|
|
209
209
|
);
|
|
210
210
|
expect(candidate.severity).toBe(AIInsightSeverity.High);
|
|
211
|
+
/*
|
|
212
|
+
* Type AND message: the type alone collides across findings (a service
|
|
213
|
+
* whose instrumentation types every failure by HTTP status renders a wall
|
|
214
|
+
* of identical rows).
|
|
215
|
+
*/
|
|
211
216
|
expect(candidate.title).toBe(
|
|
212
|
-
"Exception spike: ConnectionError at 50.0x normal rate in payments",
|
|
217
|
+
"Exception spike: ConnectionError: connection reset by peer at 50.0x normal rate in payments",
|
|
213
218
|
);
|
|
214
219
|
expect(candidate.evidence.exception).toEqual(
|
|
215
220
|
expect.objectContaining({
|