@oneuptime/common 12.0.2 → 12.0.4
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/CephCluster.ts +14 -0
- package/Models/DatabaseModels/CodeRepository.ts +14 -6
- package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +14 -0
- package/Models/DatabaseModels/DockerHost.ts +14 -0
- package/Models/DatabaseModels/GlobalOidcProject.ts +18 -0
- package/Models/DatabaseModels/GlobalSsoProject.ts +18 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/IoTFleet.ts +14 -0
- package/Models/DatabaseModels/KubernetesCluster.ts +14 -0
- package/Models/DatabaseModels/LogDropFilter.ts +9 -20
- package/Models/DatabaseModels/NetworkDevice.ts +14 -0
- package/Models/DatabaseModels/NetworkInterface.ts +18 -0
- package/Models/DatabaseModels/Project.ts +16 -2
- package/Models/DatabaseModels/ProxmoxCluster.ts +14 -0
- package/Models/DatabaseModels/Service.ts +30 -0
- package/Models/DatabaseModels/StatusPageMonitorRule.ts +911 -0
- package/Models/DatabaseModels/StatusPagePrivateUser.ts +30 -0
- package/Models/DatabaseModels/StatusPageResource.ts +73 -0
- package/Models/DatabaseModels/TraceDropFilter.ts +9 -20
- package/Models/DatabaseModels/User.ts +30 -0
- package/Server/API/AIAgentDataAPI.ts +31 -0
- package/Server/API/BaseAPI.ts +13 -2
- package/Server/API/DashboardAPI.ts +458 -12
- package/Server/API/GitHubAPI.ts +119 -283
- package/Server/API/UserAPI.ts +263 -1
- package/Server/EnvironmentConfig.ts +38 -4
- package/Server/Infrastructure/GlobalCache.ts +152 -0
- package/Server/Infrastructure/Postgres/DataSourceOptions.ts +16 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts +123 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.ts +21 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.ts +68 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.ts +100 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.ts +214 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.ts +69 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Services/AlertStateTimelineService.ts +20 -0
- package/Server/Services/AnalyticsDatabaseService.ts +72 -1
- package/Server/Services/CephClusterService.ts +26 -86
- package/Server/Services/CloudResourceService.ts +23 -83
- package/Server/Services/CodeRepositoryService.ts +105 -2
- package/Server/Services/DatabaseService.ts +296 -2
- package/Server/Services/DockerHostService.ts +19 -79
- package/Server/Services/DockerSwarmClusterService.ts +27 -88
- package/Server/Services/HostService.ts +46 -99
- package/Server/Services/IncidentStateTimelineService.ts +20 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/IoTFleetService.ts +19 -79
- package/Server/Services/KubernetesClusterService.ts +17 -78
- package/Server/Services/LabelService.ts +57 -10
- package/Server/Services/MetricTypeService.ts +84 -0
- package/Server/Services/MonitorService.ts +89 -14
- package/Server/Services/MonitorStatusTimelineService.ts +29 -0
- package/Server/Services/MonitorTemplateService.ts +65 -0
- package/Server/Services/OpenTelemetryIngestService.ts +230 -26
- package/Server/Services/PodmanHostService.ts +19 -79
- package/Server/Services/ProxmoxClusterService.ts +23 -83
- package/Server/Services/RumApplicationService.ts +19 -80
- package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +21 -0
- package/Server/Services/ServerlessFunctionService.ts +24 -85
- package/Server/Services/ServiceService.ts +299 -73
- package/Server/Services/StatusPageMonitorRuleEngineService.ts +752 -0
- package/Server/Services/StatusPageMonitorRuleService.ts +471 -0
- package/Server/Services/TelemetryEntityRelationshipService.ts +1 -0
- package/Server/Services/TelemetryEntityService.ts +1 -0
- package/Server/Services/UserService.ts +184 -0
- package/Server/Utils/AI/Toolbox/CodeTools.ts +45 -4
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +13 -0
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +157 -4
- package/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.ts +130 -0
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +170 -39
- package/Server/Utils/Monitor/MonitorResource.ts +63 -36
- package/Server/Utils/Monitor/MonitorStatusTimeline.ts +36 -0
- package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +148 -127
- package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +434 -0
- package/Server/Utils/PasswordHash.ts +306 -0
- package/Server/Utils/SingleFlight.ts +83 -0
- package/Server/Utils/StatusPage/MonitorRulePatternValidator.ts +46 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +107 -26
- package/Server/Utils/Telemetry/ResourceHeartbeat.ts +314 -0
- package/Server/Utils/Telemetry/Telemetry.ts +351 -122
- package/Tests/App/Dashboard/OverviewCustomFields.test.tsx +333 -0
- package/Tests/App/Dashboard/UserCustomFields.test.tsx +392 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
- package/Tests/Models/DatabaseModels/ColumnTransformerInvariants.test.ts +306 -0
- package/Tests/Models/DatabaseModels/NumberColumnDeserialization.test.ts +333 -0
- package/Tests/Models/DatabaseModels/StatusPageMonitorRuleModel.test.ts +190 -0
- package/Tests/Server/API/AIAgentDataRepositoryToken.test.ts +381 -0
- package/Tests/Server/API/DashboardPublicAttributeValuesAPI.test.ts +943 -0
- package/Tests/Server/API/DashboardPublicMetricsAggregateAPI.test.ts +1296 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +26 -0
- package/Tests/Server/API/DashboardPublicTemplatePayloads.test.ts +598 -0
- package/Tests/Server/API/GitHubAppInstallationBindingAPI.test.ts +539 -0
- package/Tests/Server/API/Helpers.ts +6 -1
- package/Tests/Server/API/UserProjectsAPI.test.ts +852 -0
- package/Tests/Server/Infrastructure/GlobalCache.test.ts +354 -0
- package/Tests/Server/Infrastructure/PostgresLockTimeoutOptions.test.ts +181 -0
- package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +215 -0
- package/Tests/Server/Services/AddPerUserPasswordSaltMigration.test.ts +178 -0
- package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +582 -0
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +5 -0
- package/Tests/Server/Services/CodeRepositoryInstallationBinding.test.ts +305 -0
- package/Tests/Server/Services/CodeRepositoryResolutionBinding.test.ts +147 -0
- package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +870 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlocked.test.ts +342 -0
- package/Tests/Server/Services/DropFilterSaveValidation.test.ts +245 -0
- package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +163 -15
- package/Tests/Server/Services/MetricTypeAttachServices.test.ts +222 -0
- package/Tests/Server/Services/MissingReferenceWriteGuard.test.ts +614 -0
- package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +23 -0
- package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +568 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +305 -56
- package/Tests/Server/Services/RestoreDroppedUniqueIndexesMigration.test.ts +386 -0
- package/Tests/Server/Services/RestoreServiceLowerNameIndexMigration.test.ts +240 -0
- package/Tests/Server/Services/ServiceUpdateLastSeenSplitGates.test.ts +705 -0
- package/Tests/Server/Services/StatusPageMonitorRuleEngineService.test.ts +1719 -0
- package/Tests/Server/Services/StatusPageMonitorRuleHooks.test.ts +1212 -0
- package/Tests/Server/Services/StatusPageMonitorRuleMonitorCreateHook.test.ts +228 -0
- package/Tests/Server/Services/UserServiceFirstMasterAdminElection.test.ts +885 -0
- package/Tests/Server/Services/WidenHashedStringColumnsForScryptMigration.test.ts +220 -0
- package/Tests/Server/Utils/AI/CodeTools.test.ts +47 -1
- package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +10 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +267 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +120 -0
- package/Tests/Server/Utils/CodeRepository/GitHubInstallationBinding.test.ts +292 -0
- package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +260 -13
- package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +302 -0
- package/Tests/Server/Utils/GitHubInstallationOwnershipVerification.test.ts +340 -0
- package/Tests/Server/Utils/GitHubWebhookAndTreeCacheIsolation.test.ts +250 -0
- package/Tests/Server/Utils/MetricTypeIndexConvergence.test.ts +598 -0
- package/Tests/Server/Utils/Monitor/MonitorStatusTimelineUnusableStatus.test.ts +154 -0
- package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +638 -92
- package/Tests/Server/Utils/Monitor/MonitorStepsReferenceExtractor.test.ts +724 -0
- package/Tests/Server/Utils/PasswordHash.test.ts +555 -0
- package/Tests/Server/Utils/SingleFlight.test.ts +221 -0
- package/Tests/Types/Dashboard/NetworkDashboardTemplate.test.ts +793 -0
- package/Tests/Types/Database/BigIntColumnTransformer.test.ts +147 -0
- package/Tests/Types/Database/ColumnLength.test.ts +7 -1
- package/Tests/Types/Database/DatabasePropertyTransformer.test.ts +140 -0
- package/Tests/Types/Database/NumericColumnValue.test.ts +127 -0
- package/Tests/Types/Decimal.test.ts +37 -0
- package/Tests/Types/HashedStringPerUserSalt.test.ts +476 -0
- package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +293 -0
- package/Tests/Types/Monitor/HostAlertTemplates.test.ts +249 -0
- package/Tests/Types/Monitor/IotAlertTemplates.test.ts +320 -0
- package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +271 -0
- package/Tests/Types/Monitor/SnmpVersionParsing.test.ts +152 -0
- package/Tests/Types/Port.test.ts +38 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +696 -0
- package/Tests/UI/Components/LogsHistogram.test.tsx +276 -0
- package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +489 -0
- package/Tests/UI/Components/UseLogsHistogram.test.tsx +500 -0
- package/Tests/UI/Utils/UserProjectsModelAPI.test.ts +714 -0
- package/Tests/Utils/Dashboard/Components/DashboardComponentsUtil.test.ts +120 -0
- package/Tests/Utils/Dashboard/DashboardNetworkMapComponent.test.ts +327 -0
- package/Tests/Utils/TeamMembersByProject.test.ts +655 -0
- package/Types/Dashboard/DashboardComponentType.ts +1 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.ts +40 -0
- package/Types/Dashboard/DashboardTemplates.ts +397 -0
- package/Types/Database/BigIntColumnTransformer.ts +74 -0
- package/Types/Database/ColumnLength.ts +9 -1
- package/Types/Database/DatabaseProperty.ts +26 -0
- package/Types/Database/NumericColumnValue.ts +128 -0
- package/Types/Database/TableColumn.ts +11 -0
- package/Types/Database/UnsynchronizedIndex.ts +48 -0
- package/Types/Decimal.ts +16 -4
- package/Types/HashedString.ts +139 -4
- package/Types/Permission.ts +48 -0
- package/Types/Port.ts +16 -4
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +85 -11
- package/UI/Components/LogsViewer/useLiveLogsRefresh.ts +86 -0
- package/UI/Components/LogsViewer/useLogsHistogram.ts +113 -0
- package/UI/Components/Navbar/NavBar.tsx +12 -2
- package/UI/Components/Navbar/NavBarMenuModal.tsx +19 -7
- package/UI/Utils/ModelAPI/UserProjectsModelAPI.ts +257 -0
- package/Utils/Dashboard/Components/DashboardNetworkMapComponent.ts +136 -0
- package/Utils/Dashboard/Components/Index.ts +7 -0
- package/Utils/TeamMembersByProject.ts +237 -0
- package/build/dist/Models/DatabaseModels/CephCluster.js +16 -1
- package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CodeRepository.js +14 -6
- package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +12 -0
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js +16 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +16 -1
- package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +16 -1
- package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IoTFleet.js +16 -1
- package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js +16 -1
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LogDropFilter.js +9 -20
- package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +16 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkInterface.js +16 -1
- package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +16 -2
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +16 -1
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Service.js +28 -1
- package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js +925 -0
- package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js +32 -0
- package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageResource.js +72 -0
- package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js +9 -20
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +32 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +21 -2
- package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +11 -1
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +343 -10
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/GitHubAPI.js +94 -167
- package/build/dist/Server/API/GitHubAPI.js.map +1 -1
- package/build/dist/Server/API/UserAPI.js +187 -2
- package/build/dist/Server/API/UserAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +34 -4
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/GlobalCache.js +120 -0
- package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +5 -3
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js +48 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js +59 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js +93 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js +101 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js +66 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertStateTimelineService.js +19 -0
- package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +57 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterService.js +26 -76
- package/build/dist/Server/Services/CephClusterService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceService.js +23 -73
- package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
- package/build/dist/Server/Services/CodeRepositoryService.js +90 -2
- package/build/dist/Server/Services/CodeRepositoryService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +246 -2
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostService.js +19 -69
- package/build/dist/Server/Services/DockerHostService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterService.js +27 -78
- package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
- package/build/dist/Server/Services/HostService.js +58 -102
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.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/IoTFleetService.js +19 -69
- package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterService.js +17 -68
- package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
- package/build/dist/Server/Services/LabelService.js +42 -7
- package/build/dist/Server/Services/LabelService.js.map +1 -1
- package/build/dist/Server/Services/MetricTypeService.js +74 -0
- package/build/dist/Server/Services/MetricTypeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +81 -9
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +28 -0
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +60 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +155 -25
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostService.js +19 -69
- package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterService.js +23 -73
- package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationService.js +19 -70
- package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +20 -0
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionService.js +24 -75
- package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
- package/build/dist/Server/Services/ServiceService.js +236 -61
- package/build/dist/Server/Services/ServiceService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +603 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleService.js +401 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleService.js.map +1 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +1 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryEntityService.js +1 -0
- package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +165 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js +31 -1
- package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +13 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +126 -4
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js +136 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js.map +1 -0
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +105 -29
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +56 -32
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +30 -3
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +110 -98
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +312 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -0
- package/build/dist/Server/Utils/PasswordHash.js +237 -0
- package/build/dist/Server/Utils/PasswordHash.js.map +1 -0
- package/build/dist/Server/Utils/SingleFlight.js +76 -0
- package/build/dist/Server/Utils/SingleFlight.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +29 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +78 -19
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +160 -0
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +279 -104
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +368 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Database/BigIntColumnTransformer.js +66 -0
- package/build/dist/Types/Database/BigIntColumnTransformer.js.map +1 -0
- package/build/dist/Types/Database/ColumnLength.js +9 -1
- package/build/dist/Types/Database/ColumnLength.js.map +1 -1
- package/build/dist/Types/Database/DatabaseProperty.js +25 -0
- package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
- package/build/dist/Types/Database/NumericColumnValue.js +97 -0
- package/build/dist/Types/Database/NumericColumnValue.js.map +1 -0
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/Database/UnsynchronizedIndex.js +46 -0
- package/build/dist/Types/Database/UnsynchronizedIndex.js.map +1 -0
- package/build/dist/Types/Decimal.js +14 -3
- package/build/dist/Types/Decimal.js.map +1 -1
- package/build/dist/Types/HashedString.js +95 -5
- package/build/dist/Types/HashedString.js.map +1 -1
- package/build/dist/Types/Permission.js +42 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Port.js +15 -5
- package/build/dist/Types/Port.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +51 -10
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js +44 -0
- package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +75 -0
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -0
- package/build/dist/UI/Components/Navbar/NavBar.js +3 -1
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +19 -7
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js +156 -0
- package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js +114 -0
- package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/TeamMembersByProject.js +145 -0
- package/build/dist/Utils/TeamMembersByProject.js.map +1 -0
- package/package.json +1 -1
|
@@ -24,6 +24,7 @@ import IncludesNone from "../../../../Types/BaseDatabase/IncludesNone";
|
|
|
24
24
|
import MultiSearch from "../../../../Types/BaseDatabase/MultiSearch";
|
|
25
25
|
import Search from "../../../../Types/BaseDatabase/Search";
|
|
26
26
|
import StartsWith from "../../../../Types/BaseDatabase/StartsWith";
|
|
27
|
+
import SortOrder from "../../../../Types/BaseDatabase/SortOrder";
|
|
27
28
|
import BadDataException from "../../../../Types/Exception/BadDataException";
|
|
28
29
|
|
|
29
30
|
function expectStatement(actual: Statement, expected: Statement): void {
|
|
@@ -1431,6 +1432,125 @@ describe("StatementGenerator", () => {
|
|
|
1431
1432
|
});
|
|
1432
1433
|
});
|
|
1433
1434
|
|
|
1435
|
+
/*
|
|
1436
|
+
* The separator here is load-bearing for pagination. `toSortStatement`
|
|
1437
|
+
* used to append sort keys with no delimiter, so anything past the first
|
|
1438
|
+
* key produced a malformed term (`col_1 DESCcol_2 ASC`) — which meant a
|
|
1439
|
+
* multi-key ORDER BY was unusable and, in practice, every paginated read
|
|
1440
|
+
* ran on a single, non-unique sort column. See the pagination-stability
|
|
1441
|
+
* suite in Tests/Server/Services/AnalyticsDatabasePaginationStability.
|
|
1442
|
+
*/
|
|
1443
|
+
describe("toSortStatement", () => {
|
|
1444
|
+
/*
|
|
1445
|
+
* TestModel declares its columns through `tableColumns`, not as TS
|
|
1446
|
+
* properties, so a `Sort<TestModel>` literal would fail excess-property
|
|
1447
|
+
* checking on every key. Funnelling through one helper keeps the cast
|
|
1448
|
+
* in a single place instead of on each call.
|
|
1449
|
+
*/
|
|
1450
|
+
const sortStatementFor: (sort: Record<string, SortOrder>) => Statement = (
|
|
1451
|
+
sort: Record<string, SortOrder>,
|
|
1452
|
+
): Statement => {
|
|
1453
|
+
return generator.toSortStatement(sort as any);
|
|
1454
|
+
};
|
|
1455
|
+
|
|
1456
|
+
test("renders a single ascending key with no trailing separator", () => {
|
|
1457
|
+
const statement: Statement = sortStatementFor({
|
|
1458
|
+
column_1: SortOrder.Ascending,
|
|
1459
|
+
});
|
|
1460
|
+
|
|
1461
|
+
expect(statement.query).toBe("{p0:Identifier} ASC");
|
|
1462
|
+
expect(statement.query_params).toStrictEqual({ p0: "column_1" });
|
|
1463
|
+
});
|
|
1464
|
+
|
|
1465
|
+
test("renders a single descending key", () => {
|
|
1466
|
+
const statement: Statement = sortStatementFor({
|
|
1467
|
+
column_1: SortOrder.Descending,
|
|
1468
|
+
});
|
|
1469
|
+
|
|
1470
|
+
expect(statement.query).toBe("{p0:Identifier} DESC");
|
|
1471
|
+
expect(statement.query_params).toStrictEqual({ p0: "column_1" });
|
|
1472
|
+
});
|
|
1473
|
+
|
|
1474
|
+
test("comma separates two keys", () => {
|
|
1475
|
+
const statement: Statement = sortStatementFor({
|
|
1476
|
+
column_1: SortOrder.Descending,
|
|
1477
|
+
column_2: SortOrder.Ascending,
|
|
1478
|
+
});
|
|
1479
|
+
|
|
1480
|
+
expect(statement.query).toBe("{p0:Identifier} DESC, {p1:Identifier} ASC");
|
|
1481
|
+
expect(statement.query_params).toStrictEqual({
|
|
1482
|
+
p0: "column_1",
|
|
1483
|
+
p1: "column_2",
|
|
1484
|
+
});
|
|
1485
|
+
});
|
|
1486
|
+
|
|
1487
|
+
test("comma separates three keys and preserves declaration order", () => {
|
|
1488
|
+
const statement: Statement = sortStatementFor({
|
|
1489
|
+
column_2: SortOrder.Ascending,
|
|
1490
|
+
column_1: SortOrder.Descending,
|
|
1491
|
+
column_ObjectID: SortOrder.Ascending,
|
|
1492
|
+
});
|
|
1493
|
+
|
|
1494
|
+
expect(statement.query).toBe(
|
|
1495
|
+
"{p0:Identifier} ASC, {p1:Identifier} DESC, {p2:Identifier} ASC",
|
|
1496
|
+
);
|
|
1497
|
+
expect(statement.query_params).toStrictEqual({
|
|
1498
|
+
p0: "column_2",
|
|
1499
|
+
p1: "column_1",
|
|
1500
|
+
p2: "column_ObjectID",
|
|
1501
|
+
});
|
|
1502
|
+
});
|
|
1503
|
+
|
|
1504
|
+
/*
|
|
1505
|
+
* Regression guard for the exact malformed shape. Asserting on the
|
|
1506
|
+
* rendered text rather than the param map is deliberate: the old bug
|
|
1507
|
+
* produced correct PARAMS and broken SQL, so a params-only assertion
|
|
1508
|
+
* would have passed straight through it.
|
|
1509
|
+
*/
|
|
1510
|
+
test("never concatenates a direction into the next identifier", () => {
|
|
1511
|
+
const statement: Statement = sortStatementFor({
|
|
1512
|
+
column_1: SortOrder.Descending,
|
|
1513
|
+
column_2: SortOrder.Ascending,
|
|
1514
|
+
});
|
|
1515
|
+
|
|
1516
|
+
expect(statement.query).not.toContain("DESC{");
|
|
1517
|
+
expect(statement.query).not.toContain("ASC{");
|
|
1518
|
+
expect(statement.query).toContain(", ");
|
|
1519
|
+
});
|
|
1520
|
+
|
|
1521
|
+
test("separator count is always one fewer than the key count", () => {
|
|
1522
|
+
const statement: Statement = sortStatementFor({
|
|
1523
|
+
column_ObjectID: SortOrder.Ascending,
|
|
1524
|
+
column_1: SortOrder.Ascending,
|
|
1525
|
+
column_2: SortOrder.Ascending,
|
|
1526
|
+
});
|
|
1527
|
+
|
|
1528
|
+
expect(statement.query.split(", ")).toHaveLength(3);
|
|
1529
|
+
});
|
|
1530
|
+
|
|
1531
|
+
test("an empty sort produces an empty statement", () => {
|
|
1532
|
+
const statement: Statement = sortStatementFor({});
|
|
1533
|
+
|
|
1534
|
+
expect(statement.query).toBe("");
|
|
1535
|
+
expect(statement.query_params).toStrictEqual({});
|
|
1536
|
+
});
|
|
1537
|
+
|
|
1538
|
+
test("still rejects an unknown column", () => {
|
|
1539
|
+
expect(() => {
|
|
1540
|
+
return sortStatementFor({ not_a_column: SortOrder.Ascending });
|
|
1541
|
+
}).toThrow(BadDataException);
|
|
1542
|
+
});
|
|
1543
|
+
|
|
1544
|
+
test("rejects an unknown column that appears after a valid one", () => {
|
|
1545
|
+
expect(() => {
|
|
1546
|
+
return sortStatementFor({
|
|
1547
|
+
column_1: SortOrder.Ascending,
|
|
1548
|
+
not_a_column: SortOrder.Descending,
|
|
1549
|
+
});
|
|
1550
|
+
}).toThrow(BadDataException);
|
|
1551
|
+
});
|
|
1552
|
+
});
|
|
1553
|
+
|
|
1434
1554
|
describe("toColumnsCreateStatement", () => {
|
|
1435
1555
|
test("should return the columns of a CREATE TABLE statement", () => {
|
|
1436
1556
|
const statement: Statement = generator.toColumnsCreateStatement([
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import GitHubInstallationBinding from "../../../../Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding";
|
|
2
|
+
import ProjectService from "../../../../Server/Services/ProjectService";
|
|
3
|
+
import Project from "../../../../Models/DatabaseModels/Project";
|
|
4
|
+
import CodeRepository from "../../../../Models/DatabaseModels/CodeRepository";
|
|
5
|
+
import ObjectID from "../../../../Types/ObjectID";
|
|
6
|
+
import BadDataException from "../../../../Types/Exception/BadDataException";
|
|
7
|
+
import { getColumnAccessControl } from "../../../../Types/Database/AccessControl/ColumnAccessControl";
|
|
8
|
+
import { ColumnAccessControl } from "../../../../Types/BaseDatabase/AccessControl";
|
|
9
|
+
import Permission from "../../../../Types/Permission";
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* GHSA-xx95-gmcf-7q86. A GitHub App installation ID is a small integer, and
|
|
14
|
+
* the single GitHub App JWT this instance holds mints a write-scoped `ghs_`
|
|
15
|
+
* token for whichever installation it is handed. So "which project owns this
|
|
16
|
+
* installation?" has to be answered from a record only the verified install
|
|
17
|
+
* callback can write — never from the request, and never from a row the
|
|
18
|
+
* caller was able to create in a project they happen to own.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
describe("GitHubInstallationBinding", () => {
|
|
22
|
+
let projectId: ObjectID;
|
|
23
|
+
let findOneBySpy: jest.SpyInstance;
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
projectId = ObjectID.generate();
|
|
27
|
+
findOneBySpy = jest.spyOn(ProjectService, "findOneBy");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
jest.restoreAllMocks();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
function mockBoundProject(project: Project | null): void {
|
|
35
|
+
findOneBySpy.mockResolvedValue(project);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function boundProject(): Project {
|
|
39
|
+
const project: Project = new Project();
|
|
40
|
+
project.id = projectId;
|
|
41
|
+
return project;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe("isInstallationBoundToProject", () => {
|
|
45
|
+
test("returns true when the project owns the installation", async () => {
|
|
46
|
+
mockBoundProject(boundProject());
|
|
47
|
+
|
|
48
|
+
await expect(
|
|
49
|
+
GitHubInstallationBinding.isInstallationBoundToProject({
|
|
50
|
+
projectId: projectId,
|
|
51
|
+
installationId: "12345678",
|
|
52
|
+
}),
|
|
53
|
+
).resolves.toBe(true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("returns false when no project row matches project + installation", async () => {
|
|
57
|
+
mockBoundProject(null);
|
|
58
|
+
|
|
59
|
+
await expect(
|
|
60
|
+
GitHubInstallationBinding.isInstallationBoundToProject({
|
|
61
|
+
projectId: projectId,
|
|
62
|
+
installationId: "99999999",
|
|
63
|
+
}),
|
|
64
|
+
).resolves.toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
* The whole point: the query must be AND-ed on both the project and the
|
|
69
|
+
* installation. Matching on the project alone would return true for any
|
|
70
|
+
* installation ID the caller invented.
|
|
71
|
+
*/
|
|
72
|
+
test("queries on BOTH the project id and the installation id", async () => {
|
|
73
|
+
mockBoundProject(boundProject());
|
|
74
|
+
|
|
75
|
+
await GitHubInstallationBinding.isInstallationBoundToProject({
|
|
76
|
+
projectId: projectId,
|
|
77
|
+
installationId: "12345678",
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(findOneBySpy).toHaveBeenCalledTimes(1);
|
|
81
|
+
|
|
82
|
+
const findArgs: {
|
|
83
|
+
query: { _id?: string; gitHubAppInstallationId?: string };
|
|
84
|
+
props: { isRoot?: boolean };
|
|
85
|
+
} = findOneBySpy.mock.calls[0]![0] as {
|
|
86
|
+
query: { _id?: string; gitHubAppInstallationId?: string };
|
|
87
|
+
props: { isRoot?: boolean };
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
expect(findArgs.query._id).toBe(projectId.toString());
|
|
91
|
+
expect(findArgs.query.gitHubAppInstallationId).toBe("12345678");
|
|
92
|
+
expect(findArgs.props.isRoot).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/*
|
|
96
|
+
* An empty installation ID must never be treated as "bound" — otherwise a
|
|
97
|
+
* project with no GitHub connection at all would match every repository
|
|
98
|
+
* row whose installation ID had been cleared.
|
|
99
|
+
*/
|
|
100
|
+
test("returns false for an empty installation id without querying", async () => {
|
|
101
|
+
await expect(
|
|
102
|
+
GitHubInstallationBinding.isInstallationBoundToProject({
|
|
103
|
+
projectId: projectId,
|
|
104
|
+
installationId: "",
|
|
105
|
+
}),
|
|
106
|
+
).resolves.toBe(false);
|
|
107
|
+
|
|
108
|
+
expect(findOneBySpy).not.toHaveBeenCalled();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("does not treat a different project's installation as bound", async () => {
|
|
112
|
+
// The service query is what enforces this; simulate the DB finding nothing.
|
|
113
|
+
mockBoundProject(null);
|
|
114
|
+
|
|
115
|
+
await expect(
|
|
116
|
+
GitHubInstallationBinding.isInstallationBoundToProject({
|
|
117
|
+
projectId: ObjectID.generate(),
|
|
118
|
+
installationId: "12345678",
|
|
119
|
+
}),
|
|
120
|
+
).resolves.toBe(false);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
/*
|
|
125
|
+
* The bulk-filter path. Callers listing a whole project's repositories read
|
|
126
|
+
* the binding once and compare in memory — every row in such a list is in
|
|
127
|
+
* the same project, so a per-row query would ask the same question N times.
|
|
128
|
+
*/
|
|
129
|
+
describe("getBoundInstallationId", () => {
|
|
130
|
+
test("returns the installation the project owns", async () => {
|
|
131
|
+
const project: Project = boundProject();
|
|
132
|
+
project.gitHubAppInstallationId = "12345678";
|
|
133
|
+
mockBoundProject(project);
|
|
134
|
+
|
|
135
|
+
await expect(
|
|
136
|
+
GitHubInstallationBinding.getBoundInstallationId(projectId),
|
|
137
|
+
).resolves.toBe("12345678");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
/*
|
|
141
|
+
* Null, never "" or undefined: callers compare a row's installation ID
|
|
142
|
+
* against this, and an empty string would match a row whose ID had been
|
|
143
|
+
* cleared.
|
|
144
|
+
*/
|
|
145
|
+
test("returns null for a project with no GitHub connection", async () => {
|
|
146
|
+
mockBoundProject(boundProject());
|
|
147
|
+
|
|
148
|
+
await expect(
|
|
149
|
+
GitHubInstallationBinding.getBoundInstallationId(projectId),
|
|
150
|
+
).resolves.toBeNull();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("returns null when the project does not exist", async () => {
|
|
154
|
+
mockBoundProject(null);
|
|
155
|
+
|
|
156
|
+
await expect(
|
|
157
|
+
GitHubInstallationBinding.getBoundInstallationId(projectId),
|
|
158
|
+
).resolves.toBeNull();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("reads as root, so a caller's permissions cannot blind the check", async () => {
|
|
162
|
+
mockBoundProject(boundProject());
|
|
163
|
+
|
|
164
|
+
await GitHubInstallationBinding.getBoundInstallationId(projectId);
|
|
165
|
+
|
|
166
|
+
const findArgs: {
|
|
167
|
+
query: { _id?: string };
|
|
168
|
+
props: { isRoot?: boolean };
|
|
169
|
+
} = findOneBySpy.mock.calls[0]![0] as {
|
|
170
|
+
query: { _id?: string };
|
|
171
|
+
props: { isRoot?: boolean };
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
expect(findArgs.query._id).toBe(projectId.toString());
|
|
175
|
+
expect(findArgs.props.isRoot).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe("assertInstallationBoundToProject", () => {
|
|
180
|
+
test("resolves quietly when the binding exists", async () => {
|
|
181
|
+
mockBoundProject(boundProject());
|
|
182
|
+
|
|
183
|
+
await expect(
|
|
184
|
+
GitHubInstallationBinding.assertInstallationBoundToProject({
|
|
185
|
+
projectId: projectId,
|
|
186
|
+
installationId: "12345678",
|
|
187
|
+
}),
|
|
188
|
+
).resolves.toBeUndefined();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test("throws BadDataException when the binding is missing", async () => {
|
|
192
|
+
mockBoundProject(null);
|
|
193
|
+
|
|
194
|
+
await expect(
|
|
195
|
+
GitHubInstallationBinding.assertInstallationBoundToProject({
|
|
196
|
+
projectId: projectId,
|
|
197
|
+
installationId: "99999999",
|
|
198
|
+
}),
|
|
199
|
+
).rejects.toBeInstanceOf(BadDataException);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
/*
|
|
203
|
+
* The error must not confirm that the installation exists elsewhere, or
|
|
204
|
+
* the failure message becomes the enumeration oracle the fix removed.
|
|
205
|
+
*/
|
|
206
|
+
test("does not leak the installation id or another tenant's existence", async () => {
|
|
207
|
+
mockBoundProject(null);
|
|
208
|
+
|
|
209
|
+
let thrown: Error | null = null;
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
await GitHubInstallationBinding.assertInstallationBoundToProject({
|
|
213
|
+
projectId: projectId,
|
|
214
|
+
installationId: "99999999",
|
|
215
|
+
});
|
|
216
|
+
} catch (err) {
|
|
217
|
+
thrown = err as Error;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
expect(thrown).toBeInstanceOf(BadDataException);
|
|
221
|
+
expect(thrown!.message).not.toContain("99999999");
|
|
222
|
+
expect(thrown!.message.toLowerCase()).not.toContain("another");
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
/*
|
|
228
|
+
* The binding is only trustworthy if nothing outside the verified install
|
|
229
|
+
* callback can write it. These assertions pin the column ACLs that make that
|
|
230
|
+
* true — a future permission tidy-up that re-opens either column silently
|
|
231
|
+
* reopens the vulnerability, so it should fail here first.
|
|
232
|
+
*/
|
|
233
|
+
describe("Installation-id columns are not client-writable", () => {
|
|
234
|
+
test("CodeRepository.gitHubAppInstallationId cannot be created or updated by any API caller", () => {
|
|
235
|
+
const accessControl: ColumnAccessControl = getColumnAccessControl(
|
|
236
|
+
new CodeRepository(),
|
|
237
|
+
"gitHubAppInstallationId",
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
expect(accessControl.create).toEqual([]);
|
|
241
|
+
expect(accessControl.update).toEqual([]);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test("Project.gitHubAppInstallationId cannot be created or updated by any API caller", () => {
|
|
245
|
+
const accessControl: ColumnAccessControl = getColumnAccessControl(
|
|
246
|
+
new Project(),
|
|
247
|
+
"gitHubAppInstallationId",
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
expect(accessControl.create).toEqual([]);
|
|
251
|
+
expect(accessControl.update).toEqual([]);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
/*
|
|
255
|
+
* Specifically the permissions an attacker gets for free by creating their
|
|
256
|
+
* own project. Being able to write either column from one of these is the
|
|
257
|
+
* whole exploit.
|
|
258
|
+
*/
|
|
259
|
+
test.each([
|
|
260
|
+
Permission.ProjectOwner,
|
|
261
|
+
Permission.ProjectAdmin,
|
|
262
|
+
Permission.ProjectMember,
|
|
263
|
+
Permission.CreateCodeRepository,
|
|
264
|
+
Permission.EditCodeRepository,
|
|
265
|
+
Permission.EditProject,
|
|
266
|
+
])(
|
|
267
|
+
"%s cannot write either installation-id column",
|
|
268
|
+
(permission: Permission) => {
|
|
269
|
+
const repositoryAccessControl: ColumnAccessControl =
|
|
270
|
+
getColumnAccessControl(new CodeRepository(), "gitHubAppInstallationId");
|
|
271
|
+
const projectAccessControl: ColumnAccessControl = getColumnAccessControl(
|
|
272
|
+
new Project(),
|
|
273
|
+
"gitHubAppInstallationId",
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
expect(repositoryAccessControl.create).not.toContain(permission);
|
|
277
|
+
expect(repositoryAccessControl.update).not.toContain(permission);
|
|
278
|
+
expect(projectAccessControl.create).not.toContain(permission);
|
|
279
|
+
expect(projectAccessControl.update).not.toContain(permission);
|
|
280
|
+
},
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
// Reading it stays available — the dashboard shows connection status from it.
|
|
284
|
+
test("the column remains readable so the dashboard can show connection status", () => {
|
|
285
|
+
const accessControl: ColumnAccessControl = getColumnAccessControl(
|
|
286
|
+
new CodeRepository(),
|
|
287
|
+
"gitHubAppInstallationId",
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
expect(accessControl.read.length).toBeGreaterThan(0);
|
|
291
|
+
});
|
|
292
|
+
});
|