@oneuptime/common 13.0.0 → 13.0.1
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/Alert.ts +55 -0
- package/Models/DatabaseModels/CloudResource.ts +45 -7
- package/Models/DatabaseModels/CodeRepository.ts +85 -0
- package/Models/DatabaseModels/GoogleSecOpsConnection.ts +57 -7
- package/Models/DatabaseModels/GoogleSecOpsConnectionRun.ts +263 -0
- package/Models/DatabaseModels/Incident.ts +55 -0
- package/Models/DatabaseModels/Index.ts +16 -0
- package/Models/DatabaseModels/ScheduledMaintenance.ts +55 -0
- package/Models/DatabaseModels/User.ts +51 -2
- package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +43 -2
- package/Models/DatabaseModels/UserWebAuthn.ts +17 -0
- package/Models/DatabaseModels/VMwareResource.ts +1149 -0
- package/Models/DatabaseModels/VMwareVCenter.ts +1122 -0
- package/Models/DatabaseModels/VMwareVCenterFeed.ts +625 -0
- package/Models/DatabaseModels/VMwareVCenterLabelRule.ts +514 -0
- package/Models/DatabaseModels/VMwareVCenterOwnerRule.ts +596 -0
- package/Models/DatabaseModels/VMwareVCenterOwnerTeam.ts +485 -0
- package/Models/DatabaseModels/VMwareVCenterOwnerUser.ts +484 -0
- package/Models/DatabaseModels/WorkflowVariable.ts +22 -1
- package/Server/API/AIAgentDataAPI.ts +79 -4
- package/Server/API/AIAgentGitHubAPI.ts +523 -0
- package/Server/API/AIChatAPI.ts +20 -1
- package/Server/API/BillingAPI.ts +33 -0
- package/Server/API/DashboardAPI.ts +10 -0
- package/Server/API/GitHubAPI.ts +47 -5
- package/Server/API/GoogleSecOpsConnectionAPI.ts +79 -0
- package/Server/API/UserWebAuthnAPI.ts +21 -1
- package/Server/API/VMwareResourceAPI.ts +143 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791800000000-SplitWebAuthnChallengeByPurpose.ts +68 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791900000000-AddSeverityAndStateToNotificationEmailRollup.ts +26 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1792000000000-AddVMwareTables.ts +636 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1792100000000-AddGitHubCommandSettingsToCodeRepository.ts +47 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1792200000000-AddUserWebAuthnPurpose.ts +17 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1792300000000-AddGoogleSecOpsDiagnostics.ts +83 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Middleware/IdentityRateLimit.ts +101 -0
- package/Server/Services/AIRunService.ts +13 -0
- package/Server/Services/BillingPaymentMethodService.ts +99 -28
- package/Server/Services/BillingService.ts +287 -20
- package/Server/Services/CloudResourceInstanceService.ts +70 -0
- package/Server/Services/ExceptionAggregationService.ts +1 -0
- package/Server/Services/GoogleSecOpsConnectionRunService.ts +10 -0
- package/Server/Services/GoogleSecOpsConnectionService.ts +12 -0
- package/Server/Services/Index.ts +16 -0
- package/Server/Services/LogAggregationService.ts +1 -0
- package/Server/Services/MetricAggregationService.ts +1 -0
- package/Server/Services/MobilePasskeyLoginService.ts +216 -0
- package/Server/Services/MonitorService.ts +51 -1
- package/Server/Services/MonitorTemplateService.ts +91 -29
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +132 -1
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +176 -2
- package/Server/Services/OpenTelemetryIngestService.ts +17 -0
- package/Server/Services/PayAsYouGoBillingService.ts +446 -0
- package/Server/Services/ProjectService.ts +46 -2
- package/Server/Services/ServerlessFunctionInstanceService.ts +71 -0
- package/Server/Services/TeamMemberService.ts +96 -36
- package/Server/Services/TelemetryIngestionKeyService.ts +80 -10
- package/Server/Services/TelemetryUsageBillingService.ts +95 -5
- package/Server/Services/TraceAggregationService.ts +5 -4
- package/Server/Services/UserWebAuthnService.ts +592 -133
- package/Server/Services/VMwareResourceService.ts +648 -0
- package/Server/Services/VMwareVCenterFeedService.ts +99 -0
- package/Server/Services/VMwareVCenterLabelRuleEngineService.ts +240 -0
- package/Server/Services/VMwareVCenterLabelRuleService.ts +14 -0
- package/Server/Services/VMwareVCenterOwnerRuleEngineService.ts +252 -0
- package/Server/Services/VMwareVCenterOwnerRuleService.ts +14 -0
- package/Server/Services/VMwareVCenterOwnerTeamService.ts +139 -0
- package/Server/Services/VMwareVCenterOwnerUserService.ts +133 -0
- package/Server/Services/VMwareVCenterService.ts +629 -0
- package/Server/Services/WorkflowVariableService.ts +203 -0
- package/Server/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.ts +17 -0
- package/Server/Types/Billing/MeteredPlan/TelemetryMeteredPlan.ts +31 -1
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +7 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubAgentTaskTrigger.ts +341 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubCommandAuthorizer.ts +274 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubCommandParser.ts +375 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubConversation.ts +846 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubReplyComposer.ts +360 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubRunReply.ts +421 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubWebhookEvents.ts +140 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubWebhookHandler.ts +906 -0
- package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +143 -0
- package/Server/Utils/DataSource/EgressGuard.ts +160 -15
- package/Server/Utils/Database/TruncateColumnValue.ts +1 -1
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +2 -0
- package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +33 -0
- package/Server/Utils/EmailRollup/EmailRollupWriter.ts +44 -0
- package/Server/Utils/LogRedaction.ts +2 -1
- package/Server/Utils/Monitor/MonitorAlert.ts +1 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +302 -3
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +26 -4
- package/Server/Utils/Monitor/MonitorResourceContext.ts +5 -3
- package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +14 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +26 -0
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +28 -5
- package/Server/Utils/ResourceFeed/ResourceFeedUtil.ts +3 -3
- package/Server/Utils/SecurityEvent/ConnectorErrorMessage.ts +14 -9
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.ts +116 -84
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.ts +594 -195
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.ts +466 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +5 -0
- package/Server/Utils/Telemetry/ResourceHeartbeat.ts +2 -1
- package/Server/Utils/Telemetry/TelemetryEntity.ts +181 -1
- package/Server/Utils/Telemetry/VMwareSnapshotScan.ts +1352 -0
- package/Tests/App/Accounts/LoginPasskey.test.tsx +529 -0
- package/Tests/App/Accounts/MobilePasskey.test.tsx +620 -0
- package/Tests/App/Accounts/PasswordRequirements.test.tsx +254 -0
- package/Tests/App/Accounts/RegisterPassword.test.tsx +553 -0
- package/Tests/App/Dashboard/AskAiAvailability.test.ts +224 -0
- package/Tests/App/Dashboard/AskAiDisabled.test.tsx +432 -0
- package/Tests/App/Dashboard/BackupCodes.test.tsx +414 -0
- package/Tests/App/Dashboard/BillingPaidUsageFlow.test.tsx +530 -0
- package/Tests/App/Dashboard/BillingPaymentMethodForm.test.tsx +195 -0
- package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +199 -0
- package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +198 -0
- package/Tests/App/Dashboard/CloudDocumentationMarkdown.test.ts +215 -0
- package/Tests/App/Dashboard/CloudFleetSummary.test.ts +183 -0
- package/Tests/App/Dashboard/CloudFleetSummaryComponent.test.tsx +248 -0
- package/Tests/App/Dashboard/CloudResourceTelemetryScope.test.ts +215 -0
- package/Tests/App/Dashboard/CriteriaFilterDefaults.test.ts +3 -0
- package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +441 -0
- package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +458 -0
- package/Tests/App/Dashboard/DashboardToolbarPopupLayering.test.tsx +566 -0
- package/Tests/App/Dashboard/DiscoveryScanLivePage.test.tsx +376 -0
- package/Tests/App/Dashboard/DiscoveryScanLiveUpdates.test.tsx +642 -0
- package/Tests/App/Dashboard/DiscoveryScanProgress.test.tsx +267 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +69 -231
- package/Tests/App/Dashboard/GoogleSecOpsConnectionsErrors.test.tsx +244 -0
- package/Tests/App/Dashboard/GoogleSecOpsDiagnostics.test.tsx +724 -0
- package/Tests/App/Dashboard/MonitorTemplateSyncFields.test.tsx +539 -0
- package/Tests/App/Dashboard/OnCallLayerCardOverrides.test.tsx +24 -7
- package/Tests/App/Dashboard/OnCallOverridePresentation.test.ts +496 -0
- package/Tests/App/Dashboard/OnCallScheduleOverrideClarity.test.tsx +677 -0
- package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +31 -3
- package/Tests/App/Dashboard/PaidUsageConsent.test.tsx +180 -0
- package/Tests/App/Dashboard/PasskeySettings.test.tsx +1220 -0
- package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +176 -275
- package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +380 -233
- package/Tests/App/Dashboard/ProductMenuBreadcrumbs.test.tsx +3 -23
- package/Tests/App/Dashboard/ResourceFeed.test.tsx +1 -0
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +8 -1
- package/Tests/App/Dashboard/TwoFactorStatus.test.tsx +260 -0
- package/Tests/App/Dashboard/VMwareDashboardWidgets.test.ts +573 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
- package/Tests/App/Dashboard/WorkflowVariablesTable.test.tsx +768 -0
- package/Tests/App/StatusPage/StatusPageOverviewLiveAndSearch.test.tsx +532 -40
- package/Tests/App/StatusPage/StatusPageResourceSearchBox.test.tsx +19 -2
- package/Tests/Fixtures/MobilePasskeyUser.json +8 -0
- package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +25 -6
- package/Tests/Models/DatabaseModels/VMwareModels.test.ts +1134 -0
- package/Tests/Models/RunnerVersionLabel.test.ts +4 -2
- package/Tests/Server/API/AIChatProvidersAIEnabled.test.ts +259 -0
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +31 -2
- package/Tests/Server/API/BillingPayAsYouGoStatus.test.ts +116 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +29 -1
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +13 -2
- package/Tests/Server/API/GitHubWebhookSignature.test.ts +368 -0
- package/Tests/Server/API/GoogleSecOpsConnectionAPI.test.ts +248 -0
- package/Tests/Server/API/UserWebAuthnAuthenticationOptionsRoute.test.ts +330 -0
- package/Tests/Server/API/UserWebAuthnPasskeyAPI.test.ts +172 -0
- package/Tests/Server/API/VMwareResourceAPI.test.ts +546 -0
- package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupMetadataMigration.test.ts +85 -0
- package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +34 -3
- package/Tests/Server/Middleware/PasskeyRateLimit.test.ts +141 -0
- package/Tests/Server/Services/AutoImportRuleRearmRecentScans.test.ts +343 -0
- package/Tests/Server/Services/AutoImportRuleWriteRearmsScans.test.ts +381 -0
- package/Tests/Server/Services/BillingPaymentMethodServiceSync.test.ts +175 -0
- package/Tests/Server/Services/BillingService.test.ts +26 -11
- package/Tests/Server/Services/BillingServiceMeteredPaymentAuthorization.test.ts +245 -0
- package/Tests/Server/Services/BillingServicePaymentMethodReads.test.ts +362 -0
- package/Tests/Server/Services/CloudResourceInstanceStalePrune.test.ts +188 -0
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +16 -2
- package/Tests/Server/Services/GoogleSecOpsDiagnosticsModel.test.ts +153 -0
- package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +13 -0
- package/Tests/Server/Services/InventoryItemPromotionGate.test.ts +5 -0
- package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +36 -0
- package/Tests/Server/Services/InventoryUpsertTruncationGuard.test.ts +151 -0
- package/Tests/Server/Services/MobilePasskeyLoginIntegration.test.ts +231 -0
- package/Tests/Server/Services/MobilePasskeyLoginService.test.ts +315 -0
- package/Tests/Server/Services/MonitorPayAsYouGoBilling.test.ts +302 -0
- package/Tests/Server/Services/MonitorTemplateServiceFieldSync.test.ts +994 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +22 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +7 -1
- package/Tests/Server/Services/PayAsYouGoBillingService.test.ts +857 -0
- package/Tests/Server/Services/PayAsYouGoStripeRateLimitBudget.test.ts +379 -0
- package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +99 -1
- package/Tests/Server/Services/ProjectServiceSubscriptionSeats.test.ts +134 -0
- package/Tests/Server/Services/ResourceFeedServices.test.ts +3 -2
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +32 -6
- package/Tests/Server/Services/SecurityEventLastErrorColumnWidth.test.ts +363 -175
- package/Tests/Server/Services/ServerlessFunctionInstanceStalePrune.test.ts +200 -0
- package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +3 -0
- package/Tests/Server/Services/TeamMemberBillingSeatSync.test.ts +762 -0
- package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +3 -0
- package/Tests/Server/Services/TelemetryIngestionKeyPolicyResolution.test.ts +72 -0
- package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +17 -4
- package/Tests/Server/Services/TelemetryPayAsYouGoBilling.test.ts +355 -0
- package/Tests/Server/Services/TraceAnalyticsResourceDisplayNames.test.ts +41 -4
- package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +37 -0
- package/Tests/Server/Services/UserWebAuthnPasskeyIntegration.test.ts +401 -0
- package/Tests/Server/Services/UserWebAuthnPasskeyService.test.ts +769 -0
- package/Tests/Server/Services/UserWebAuthnUserVerification.test.ts +649 -0
- package/Tests/Server/Services/VMwareResourceService.test.ts +945 -0
- package/Tests/Server/Services/VMwareVCenterService.test.ts +722 -0
- package/Tests/Server/Services/WorkflowVariableRenameUniqueness.test.ts +842 -0
- package/Tests/Server/TestingUtils/PasskeyHttpIntegration.ts +102 -0
- package/Tests/Server/TestingUtils/SecurityKey.ts +464 -0
- package/Tests/Server/TestingUtils/WebAuthnServiceMocks.ts +60 -0
- package/Tests/Server/Types/Billing/PayAsYouGoMeteredAuthorization.test.ts +573 -0
- package/Tests/Server/Types/Database/Permissions/ProjectCustomerSupportAccessColumn.test.ts +261 -0
- package/Tests/Server/Types/Database/Permissions/WorkflowVariableColumnPermission.test.ts +95 -0
- package/Tests/Server/Utils/CodeRepository/GitHubAgentTaskTrigger.test.ts +2101 -0
- package/Tests/Server/Utils/CodeRepository/GitHubCommandAuthorizer.test.ts +883 -0
- package/Tests/Server/Utils/CodeRepository/GitHubCommandParser.test.ts +1474 -0
- package/Tests/Server/Utils/CodeRepository/GitHubConversation.test.ts +1526 -0
- package/Tests/Server/Utils/CodeRepository/GitHubReplyComposer.test.ts +1389 -0
- package/Tests/Server/Utils/CodeRepository/GitHubRunReply.test.ts +1707 -0
- package/Tests/Server/Utils/CodeRepository/GitHubWebhookHandler.test.ts +2202 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +345 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +896 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupMetadataIntegration.test.ts +246 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +299 -1
- package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +6 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +185 -0
- package/Tests/Server/Utils/LogRedaction.test.ts +33 -0
- package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +2 -1
- package/Tests/Server/Utils/Monitor/Criteria/TelemetryStepMetricAlias.test.ts +10 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +66 -1
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +362 -0
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +60 -1
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +60 -0
- package/Tests/Server/Utils/Monitor/MonitorRootCauseTargetResolution.test.ts +423 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +6 -0
- package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/PerSeriesSecondEntityAlerting.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +46 -2
- package/Tests/Server/Utils/SecurityEvent/ConnectorErrorMessage.test.ts +81 -45
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.test.ts +711 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClickhouseIntegration.test.ts +223 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClient.test.ts +69 -1
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsDiagnostics.test.ts +838 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsErrorHandling.test.ts +241 -28
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsHttpIntegration.test.ts +651 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +11 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerFailureTaxonomy.test.ts +13 -12
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerHardening.test.ts +112 -127
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsRequestContract.test.ts +12 -18
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsResponseParsing.test.ts +43 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +580 -0
- package/Tests/Server/Utils/Telemetry/VMwareSnapshotScan.test.ts +1748 -0
- package/Tests/Types/Cloud/CloudPlatform.test.ts +574 -0
- package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +2 -0
- package/Tests/Types/Monitor/MonitorCriteriaMetricVariables.test.ts +9 -0
- package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorStepInfraMonitorUtils.test.ts +53 -8
- package/Tests/Types/Monitor/MonitorStepInfrastructureMonitors.test.ts +97 -0
- package/Tests/Types/Monitor/MonitorStepMetricViewConfigUtil.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorStepTemplateSyncFields.test.ts +107 -0
- package/Tests/Types/Monitor/MonitorTemplateSyncField.test.ts +172 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +2 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationAlertDebuggability.test.ts +1 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +9 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +1 -1
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +1 -1
- package/Tests/Types/Monitor/SeriesContext/SeriesDebugHints.test.ts +131 -0
- package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +10 -0
- package/Tests/Types/Monitor/VMwareAlertTemplates.test.ts +1608 -0
- package/Tests/Types/Monitor/VMwareMetricCatalog.test.ts +488 -0
- package/Tests/Types/OnCallDutyPolicy/OverrideProvenance.test.ts +295 -0
- package/Tests/Types/Runner/RunnerLiveStatus.test.ts +2 -2
- package/Tests/Types/SignupPassword.test.ts +205 -0
- package/Tests/Types/StatusPage/StatusPageLanguage.test.ts +44 -0
- package/Tests/Types/SupportedLanguages.test.ts +119 -0
- package/Tests/Types/Telemetry/EntityTypeGroups.test.ts +19 -0
- package/Tests/UI/ColorPickerBuild.test.ts +86 -0
- package/Tests/UI/Components/Breadcrumbs.test.tsx +32 -0
- package/Tests/UI/Components/Forms/ModelFormPreservesUserInput.test.tsx +937 -0
- package/Tests/UI/Components/Forms/ModelFormWriteOnlyColumnSelect.test.tsx +230 -0
- package/Tests/UI/Components/Forms/ValidationFormSteps.test.ts +3 -4
- package/Tests/UI/Components/LabelRuleImportExport.test.tsx +907 -0
- package/Tests/UI/Components/ModelTable/ModelTableCreateAfterEdit.test.tsx +514 -0
- package/Tests/UI/Components/MonitorGraphs/Uptime.test.tsx +301 -0
- package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +2 -1
- package/Tests/UI/Components/TooltipLazyContent.test.tsx +373 -0
- package/Tests/UI/MicrosoftTeams/MicrosoftTeamsMessagingEndpointGuidance.test.tsx +43 -12
- package/Tests/UI/ReactDomBuild.test.ts +104 -0
- package/Tests/UI/ReactRouterSingletonBuild.test.ts +11 -1
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +148 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +29 -0
- package/Tests/UI/Utils/DashboardStackingLayers.test.ts +197 -0
- package/Tests/UI/Utils/LabelRuleImportExport.test.ts +546 -0
- package/Tests/UI/Utils/ModelAPITenantHeader.test.ts +109 -2
- package/Tests/UI/Utils/UseDashboardGridDnd.test.tsx +7 -2
- package/Tests/UI/Utils/UserEmailRegistrationStatus.test.tsx +295 -0
- package/Tests/UI/Utils/WebAuthn.test.ts +265 -0
- package/Tests/Utils/Dashboard/Components/DashboardComponentDefaults.test.ts +5 -0
- package/Tests/Utils/Dashboard/Components/DashboardVMwareListComponents.test.ts +548 -0
- package/Tests/Utils/Dashboard/DashboardResourceListSharedArgs.test.ts +17 -3
- package/Tests/Utils/LabelRuleImportExport.test.ts +583 -0
- package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
- package/Tests/Utils/Monitor/MonitorTemplateSyncUtil.test.ts +590 -0
- package/Tests/Utils/RequestFailedDetails.test.ts +325 -0
- package/Tests/Utils/Telemetry/CloudInstanceIdentity.test.ts +255 -0
- package/Tests/Utils/Telemetry/EntityRelationship.test.ts +167 -0
- package/Tests/Utils/WebAuthnTestUtil.ts +79 -0
- package/Tests/__mocks__/simplewebauthn.js +33 -4
- package/Types/AI/CodeFixTaskContext.ts +122 -0
- package/Types/AI/CodeFixTaskType.ts +62 -0
- package/Types/Accounts/AccountsLanguage.ts +1 -0
- package/Types/AdminDashboard/AdminDashboardLanguage.ts +1 -0
- package/Types/Calendar/CalendarEvent.ts +16 -0
- package/Types/Cloud/CloudPlatform.ts +372 -0
- package/Types/CodeRepository/GitHubCommand.ts +69 -0
- package/Types/Dashboard/DashboardComponentType.ts +2 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardVMwareHostListComponent.ts +23 -0
- package/Types/Dashboard/DashboardComponents/DashboardVMwareVirtualMachineListComponent.ts +30 -0
- package/Types/Dashboard/DashboardLanguage.ts +1 -0
- package/Types/Dashboard/DashboardTemplates.ts +314 -0
- package/Types/Docs/DocsLanguage.ts +1 -0
- package/Types/Exception/EgressGuardException.ts +65 -0
- package/Types/Icon/IconProp.ts +1 -0
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +36 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +1 -0
- package/Types/Monitor/MonitorStep.ts +78 -17
- package/Types/Monitor/MonitorStepMetricViewConfigUtil.ts +1 -0
- package/Types/Monitor/MonitorStepVMwareMonitor.ts +127 -0
- package/Types/Monitor/MonitorTemplateSyncField.ts +291 -0
- package/Types/Monitor/MonitorType.ts +24 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +33 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +2 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +3 -0
- package/Types/Monitor/SeriesContext/SeriesDebugHints.ts +158 -0
- package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +61 -0
- package/Types/Monitor/VMwareAlertTemplates.ts +1070 -0
- package/Types/Monitor/VMwareMetricCatalog.ts +914 -0
- package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +29 -0
- package/Types/OnCallDutyPolicy/UserOverrideUtil.ts +16 -0
- package/Types/Password.ts +84 -5
- package/Types/Permission.ts +265 -0
- package/Types/Probe/RequestFailedDetails.ts +7 -0
- package/Types/Runner/RunnerLiveStatus.ts +1 -1
- package/Types/SecurityEvent/GoogleSecOpsDiagnostics.ts +56 -0
- package/Types/StatusPage/StatusPageLanguage.ts +1 -0
- package/Types/Telemetry/EntityType.ts +21 -0
- package/Types/Telemetry/ServiceType.ts +1 -0
- package/Typings/Index.d.ts +63 -0
- package/UI/Components/Breadcrumbs/Breadcrumbs.tsx +2 -2
- package/UI/Components/Calendar/Calendar.css +78 -0
- package/UI/Components/Calendar/Calendar.tsx +28 -3
- package/UI/Components/Forms/BasicForm.tsx +44 -2
- package/UI/Components/Forms/Fields/ColorPicker.tsx +2 -1
- package/UI/Components/Forms/Fields/FormField.tsx +16 -3
- package/UI/Components/Forms/ModelForm.tsx +159 -5
- package/UI/Components/Forms/Types/Field.ts +8 -1
- package/UI/Components/Graphs/DayUptimeGraph.tsx +8 -10
- package/UI/Components/Icon/Icon.tsx +16 -0
- package/UI/Components/Input/Input.tsx +42 -7
- package/UI/Components/LabelRule/ImportLabelRulesModal.tsx +441 -0
- package/UI/Components/LabelRule/LabelRuleTable.tsx +142 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +22 -5
- package/UI/Components/ModelTable/ModelTable.tsx +14 -6
- package/UI/Components/MonitorGraphs/Uptime.tsx +17 -27
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +3 -1
- package/UI/Components/Tooltip/Tooltip.tsx +52 -6
- package/UI/Utils/DashboardStackingLayers.ts +85 -0
- package/UI/Utils/LabelRuleImportExport.ts +310 -0
- package/UI/Utils/ModelAPI/ModelAPI.ts +4 -3
- package/UI/Utils/TelemetryService.ts +4 -3
- package/UI/Utils/UseDashboardGridDnd.ts +4 -1
- package/UI/Utils/UserEmailRegistrationStatus.ts +33 -5
- package/UI/Utils/WebAuthn.ts +220 -0
- package/UI/esbuild-config.js +4 -0
- package/Utils/API.ts +34 -0
- package/Utils/Dashboard/Components/DashboardVMwareHostListComponent.ts +38 -0
- package/Utils/Dashboard/Components/DashboardVMwareResourceListShared.ts +70 -0
- package/Utils/Dashboard/Components/DashboardVMwareVirtualMachineListComponent.ts +76 -0
- package/Utils/Dashboard/Components/Index.ts +16 -0
- package/Utils/LabelRuleImportExport.ts +496 -0
- package/Utils/Monitor/MonitorTemplateSyncUtil.ts +164 -0
- package/Utils/NetworkDiscovery/DiscoveryScanStatus.ts +8 -0
- package/Utils/Telemetry/CloudInstanceIdentity.ts +94 -0
- package/Utils/Telemetry/EntityKey.ts +19 -0
- package/Utils/Telemetry/EntityRelationship.ts +19 -0
- package/build/dist/Models/DatabaseModels/Alert.js +54 -0
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CloudResource.js +44 -7
- package/build/dist/Models/DatabaseModels/CloudResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CodeRepository.js +87 -0
- package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +60 -7
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnectionRun.js +287 -0
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnectionRun.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Incident.js +54 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +16 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +54 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +57 -4
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +47 -2
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWebAuthn.js +18 -0
- package/build/dist/Models/DatabaseModels/UserWebAuthn.js.map +1 -1
- package/build/dist/Models/DatabaseModels/VMwareResource.js +1201 -0
- package/build/dist/Models/DatabaseModels/VMwareResource.js.map +1 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js +1149 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterFeed.js +648 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterLabelRule.js +522 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerRule.js +603 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerTeam.js +503 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerUser.js +502 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js +22 -1
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +63 -3
- package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
- package/build/dist/Server/API/AIAgentGitHubAPI.js +363 -0
- package/build/dist/Server/API/AIAgentGitHubAPI.js.map +1 -0
- package/build/dist/Server/API/AIChatAPI.js +19 -1
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/BillingAPI.js +22 -0
- package/build/dist/Server/API/BillingAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +10 -0
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/GitHubAPI.js +33 -5
- package/build/dist/Server/API/GitHubAPI.js.map +1 -1
- package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js +56 -0
- package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js.map +1 -0
- package/build/dist/Server/API/UserWebAuthnAPI.js +17 -1
- package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -1
- package/build/dist/Server/API/VMwareResourceAPI.js +106 -0
- package/build/dist/Server/API/VMwareResourceAPI.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791800000000-SplitWebAuthnChallengeByPurpose.js +41 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791800000000-SplitWebAuthnChallengeByPurpose.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791900000000-AddSeverityAndStateToNotificationEmailRollup.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791900000000-AddSeverityAndStateToNotificationEmailRollup.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792000000000-AddVMwareTables.js +241 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792000000000-AddVMwareTables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792100000000-AddGitHubCommandSettingsToCodeRepository.js +36 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792100000000-AddGitHubCommandSettingsToCodeRepository.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792200000000-AddUserWebAuthnPurpose.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792200000000-AddUserWebAuthnPurpose.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792300000000-AddGoogleSecOpsDiagnostics.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792300000000-AddGoogleSecOpsDiagnostics.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/Middleware/IdentityRateLimit.js +80 -0
- package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +14 -1
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/BillingPaymentMethodService.js +71 -21
- package/build/dist/Server/Services/BillingPaymentMethodService.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +210 -22
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceInstanceService.js +66 -0
- package/build/dist/Server/Services/CloudResourceInstanceService.js.map +1 -1
- package/build/dist/Server/Services/ExceptionAggregationService.js +1 -0
- package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
- package/build/dist/Server/Services/GoogleSecOpsConnectionRunService.js +9 -0
- package/build/dist/Server/Services/GoogleSecOpsConnectionRunService.js.map +1 -0
- package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +7 -0
- package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +16 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +1 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricAggregationService.js +1 -0
- package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MobilePasskeyLoginService.js +137 -0
- package/build/dist/Server/Services/MobilePasskeyLoginService.js.map +1 -0
- package/build/dist/Server/Services/MonitorService.js +34 -1
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +64 -26
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +124 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +142 -2
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +28 -13
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/PayAsYouGoBillingService.js +297 -0
- package/build/dist/Server/Services/PayAsYouGoBillingService.js.map +1 -0
- package/build/dist/Server/Services/ProjectService.js +38 -2
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionInstanceService.js +66 -0
- package/build/dist/Server/Services/ServerlessFunctionInstanceService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +85 -28
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js +61 -10
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +62 -5
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +5 -4
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Services/UserWebAuthnService.js +345 -113
- package/build/dist/Server/Services/UserWebAuthnService.js.map +1 -1
- package/build/dist/Server/Services/VMwareResourceService.js +395 -0
- package/build/dist/Server/Services/VMwareResourceService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterFeedService.js +89 -0
- package/build/dist/Server/Services/VMwareVCenterFeedService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterLabelRuleEngineService.js +197 -0
- package/build/dist/Server/Services/VMwareVCenterLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterLabelRuleService.js +13 -0
- package/build/dist/Server/Services/VMwareVCenterLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerRuleEngineService.js +214 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerTeamService.js +129 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerUserService.js +122 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterService.js +533 -0
- package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -0
- package/build/dist/Server/Services/WorkflowVariableService.js +169 -0
- package/build/dist/Server/Services/WorkflowVariableService.js.map +1 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.js +12 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.js.map +1 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/TelemetryMeteredPlan.js +25 -2
- package/build/dist/Server/Types/Billing/MeteredPlan/TelemetryMeteredPlan.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubAgentTaskTrigger.js +275 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubAgentTaskTrigger.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubCommandAuthorizer.js +226 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubCommandAuthorizer.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubCommandParser.js +297 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubCommandParser.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubConversation.js +582 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubConversation.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubReplyComposer.js +275 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubReplyComposer.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubRunReply.js +365 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubRunReply.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubWebhookEvents.js +103 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubWebhookEvents.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubWebhookHandler.js +661 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubWebhookHandler.js.map +1 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +113 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +99 -15
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +2 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +18 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +31 -2
- package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -1
- package/build/dist/Server/Utils/LogRedaction.js +2 -1
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +219 -4
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +12 -4
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +5 -3
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +22 -9
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +21 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +21 -6
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
- package/build/dist/Server/Utils/ResourceFeed/ResourceFeedUtil.js +3 -3
- package/build/dist/Server/Utils/SecurityEvent/ConnectorErrorMessage.js +9 -9
- package/build/dist/Server/Utils/SecurityEvent/ConnectorErrorMessage.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js +92 -71
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +428 -143
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js +376 -0
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +5 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +136 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/VMwareSnapshotScan.js +933 -0
- package/build/dist/Server/Utils/Telemetry/VMwareSnapshotScan.js.map +1 -0
- package/build/dist/Types/AI/CodeFixTaskContext.js +40 -0
- package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -1
- package/build/dist/Types/AI/CodeFixTaskType.js +57 -0
- package/build/dist/Types/AI/CodeFixTaskType.js.map +1 -1
- package/build/dist/Types/Accounts/AccountsLanguage.js +1 -0
- package/build/dist/Types/Accounts/AccountsLanguage.js.map +1 -1
- package/build/dist/Types/AdminDashboard/AdminDashboardLanguage.js +1 -0
- package/build/dist/Types/AdminDashboard/AdminDashboardLanguage.js.map +1 -1
- package/build/dist/Types/Cloud/CloudPlatform.js +277 -0
- package/build/dist/Types/Cloud/CloudPlatform.js.map +1 -0
- package/build/dist/Types/CodeRepository/GitHubCommand.js +52 -0
- package/build/dist/Types/CodeRepository/GitHubCommand.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js +2 -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/DashboardVMwareHostListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardVMwareHostListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardVMwareVirtualMachineListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardVMwareVirtualMachineListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardLanguage.js +1 -0
- package/build/dist/Types/Dashboard/DashboardLanguage.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.js +286 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Docs/DocsLanguage.js +1 -0
- package/build/dist/Types/Docs/DocsLanguage.js.map +1 -1
- package/build/dist/Types/Exception/EgressGuardException.js +59 -0
- package/build/dist/Types/Exception/EgressGuardException.js.map +1 -0
- package/build/dist/Types/Icon/IconProp.js +1 -0
- package/build/dist/Types/Icon/IconProp.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +1 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +61 -18
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js +1 -0
- package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepVMwareMonitor.js +71 -0
- package/build/dist/Types/Monitor/MonitorStepVMwareMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorTemplateSyncField.js +211 -0
- package/build/dist/Types/Monitor/MonitorTemplateSyncField.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorType.js +23 -0
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +28 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +2 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
- package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js +120 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js.map +1 -1
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +60 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -1
- package/build/dist/Types/Monitor/VMwareAlertTemplates.js +775 -0
- package/build/dist/Types/Monitor/VMwareAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/VMwareMetricCatalog.js +799 -0
- package/build/dist/Types/Monitor/VMwareMetricCatalog.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +25 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js +5 -0
- package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js.map +1 -1
- package/build/dist/Types/Password.js +63 -5
- package/build/dist/Types/Password.js.map +1 -1
- package/build/dist/Types/Permission.js +234 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Probe/RequestFailedDetails.js +7 -0
- package/build/dist/Types/Probe/RequestFailedDetails.js.map +1 -1
- package/build/dist/Types/SecurityEvent/GoogleSecOpsDiagnostics.js +2 -0
- package/build/dist/Types/SecurityEvent/GoogleSecOpsDiagnostics.js.map +1 -0
- package/build/dist/Types/StatusPage/StatusPageLanguage.js +1 -0
- package/build/dist/Types/StatusPage/StatusPageLanguage.js.map +1 -1
- package/build/dist/Types/Telemetry/EntityType.js +21 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
- package/build/dist/Types/Telemetry/ServiceType.js +1 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
- package/build/dist/UI/Components/Breadcrumbs/Breadcrumbs.js +2 -2
- package/build/dist/UI/Components/Breadcrumbs/Breadcrumbs.js.map +1 -1
- package/build/dist/UI/Components/Calendar/Calendar.js +24 -4
- package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +28 -3
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/ColorPicker.js +1 -1
- package/build/dist/UI/Components/Forms/Fields/ColorPicker.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +10 -3
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Forms/ModelForm.js +89 -6
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +5 -6
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +14 -0
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +37 -8
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/LabelRule/ImportLabelRulesModal.js +228 -0
- package/build/dist/UI/Components/LabelRule/ImportLabelRulesModal.js.map +1 -0
- package/build/dist/UI/Components/LabelRule/LabelRuleTable.js +102 -0
- package/build/dist/UI/Components/LabelRule/LabelRuleTable.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +15 -2
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ModelTable.js +13 -5
- package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js +14 -15
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +2 -0
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js +33 -4
- package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
- package/build/dist/UI/Utils/DashboardStackingLayers.js +44 -0
- package/build/dist/UI/Utils/DashboardStackingLayers.js.map +1 -0
- package/build/dist/UI/Utils/LabelRuleImportExport.js +195 -0
- package/build/dist/UI/Utils/LabelRuleImportExport.js.map +1 -0
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +4 -4
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/TelemetryService.js +3 -2
- package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
- package/build/dist/UI/Utils/UseDashboardGridDnd.js +2 -1
- package/build/dist/UI/Utils/UseDashboardGridDnd.js.map +1 -1
- package/build/dist/UI/Utils/UserEmailRegistrationStatus.js +21 -4
- package/build/dist/UI/Utils/UserEmailRegistrationStatus.js.map +1 -1
- package/build/dist/UI/Utils/WebAuthn.js +121 -0
- package/build/dist/UI/Utils/WebAuthn.js.map +1 -0
- package/build/dist/Utils/API.js +29 -0
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardVMwareHostListComponent.js +33 -0
- package/build/dist/Utils/Dashboard/Components/DashboardVMwareHostListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardVMwareResourceListShared.js +54 -0
- package/build/dist/Utils/Dashboard/Components/DashboardVMwareResourceListShared.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardVMwareVirtualMachineListComponent.js +60 -0
- package/build/dist/Utils/Dashboard/Components/DashboardVMwareVirtualMachineListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +8 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/LabelRuleImportExport.js +356 -0
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorTemplateSyncUtil.js +110 -0
- package/build/dist/Utils/Monitor/MonitorTemplateSyncUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js +6 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js.map +1 -1
- package/build/dist/Utils/Telemetry/CloudInstanceIdentity.js +88 -0
- package/build/dist/Utils/Telemetry/CloudInstanceIdentity.js.map +1 -0
- package/build/dist/Utils/Telemetry/EntityKey.js +15 -0
- package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
- package/build/dist/Utils/Telemetry/EntityRelationship.js +13 -0
- package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,842 @@
|
|
|
1
|
+
import WorkflowVariableService from "../../../Server/Services/WorkflowVariableService";
|
|
2
|
+
import { OnUpdate } from "../../../Server/Types/Database/Hooks";
|
|
3
|
+
import UpdateBy from "../../../Server/Types/Database/UpdateBy";
|
|
4
|
+
import WorkflowVariable from "../../../Models/DatabaseModels/WorkflowVariable";
|
|
5
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
6
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
7
|
+
import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
|
|
8
|
+
import PositiveNumber from "../../../Types/PositiveNumber";
|
|
9
|
+
import { afterEach, describe, expect, jest, test } from "@jest/globals";
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* Workflow variables became editable from the dashboard, which made renaming a
|
|
13
|
+
* variable possible for the first time. Renaming is the one write that can put
|
|
14
|
+
* two rows with the same name in the same scope:
|
|
15
|
+
*
|
|
16
|
+
* - @UniqueColumnBy(["workflowId", "projectId"]) on `name` is enforced by
|
|
17
|
+
* DatabaseService.checkUniqueColumnBy, and _updateBy never calls it;
|
|
18
|
+
* - there is no unique index on WorkflowVariable to catch what it misses
|
|
19
|
+
* (the initial migration creates plain indexes on projectId and workflowId
|
|
20
|
+
* and nothing else).
|
|
21
|
+
*
|
|
22
|
+
* The damage is silent. RunWorkflow.getVariables builds
|
|
23
|
+
* `storageMap.local.variables[variable.name] = variable.content`, a plain
|
|
24
|
+
* dictionary, so a duplicate does not error - the second row overwrites the
|
|
25
|
+
* first and {{local.variables.X}} resolves to whichever row the query happened
|
|
26
|
+
* to return last. Nothing looks broken; the workflow just runs on the wrong
|
|
27
|
+
* value, possibly the wrong credential.
|
|
28
|
+
*
|
|
29
|
+
* These drive the hook directly. It is protected, and an ordinary prototype
|
|
30
|
+
* method at runtime, so it is reached through a structural cast - going through
|
|
31
|
+
* updateBy() instead would drag in the entire ORM to prove one comparison.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
35
|
+
"aaaa1111-1111-4111-8111-111111111111",
|
|
36
|
+
);
|
|
37
|
+
const OTHER_PROJECT_ID: ObjectID = new ObjectID(
|
|
38
|
+
"bbbb1111-1111-4111-8111-111111111111",
|
|
39
|
+
);
|
|
40
|
+
const WORKFLOW_ID: ObjectID = new ObjectID(
|
|
41
|
+
"aaaa2222-2222-4222-8222-222222222222",
|
|
42
|
+
);
|
|
43
|
+
const VARIABLE_ID: ObjectID = new ObjectID(
|
|
44
|
+
"aaaa3333-3333-4333-8333-333333333333",
|
|
45
|
+
);
|
|
46
|
+
const USER_ID: ObjectID = new ObjectID("aaaa5555-5555-4555-8555-555555555555");
|
|
47
|
+
const OTHER_VARIABLE_ID: ObjectID = new ObjectID(
|
|
48
|
+
"aaaa4444-4444-4444-8444-444444444444",
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
interface ServiceInternals {
|
|
52
|
+
onBeforeUpdate: (
|
|
53
|
+
updateBy: UpdateBy<WorkflowVariable>,
|
|
54
|
+
) => Promise<OnUpdate<WorkflowVariable>>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function hook(): ServiceInternals["onBeforeUpdate"] {
|
|
58
|
+
const internals: ServiceInternals =
|
|
59
|
+
WorkflowVariableService as unknown as ServiceInternals;
|
|
60
|
+
|
|
61
|
+
return internals.onBeforeUpdate.bind(WorkflowVariableService);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
type MakeVariableOptions = {
|
|
65
|
+
id?: ObjectID | undefined;
|
|
66
|
+
name: string;
|
|
67
|
+
workflowId?: ObjectID | undefined;
|
|
68
|
+
projectId?: ObjectID | undefined;
|
|
69
|
+
isSecret?: boolean | string | undefined;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
function makeVariable(options: MakeVariableOptions): WorkflowVariable {
|
|
73
|
+
const variable: WorkflowVariable = new WorkflowVariable();
|
|
74
|
+
|
|
75
|
+
variable._id = (options.id || VARIABLE_ID).toString();
|
|
76
|
+
variable.name = options.name;
|
|
77
|
+
variable.projectId = options.projectId || PROJECT_ID;
|
|
78
|
+
|
|
79
|
+
if (options.workflowId) {
|
|
80
|
+
variable.workflowId = options.workflowId;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (options.isSecret !== undefined) {
|
|
84
|
+
(variable as unknown as { isSecret?: unknown }).isSecret = options.isSecret;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return variable;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/*
|
|
91
|
+
* Built structurally and cast through unknown. UpdateBy's `data` is a
|
|
92
|
+
* PartialEntity, whose conditional mapped type over a model with relation
|
|
93
|
+
* columns is deep enough that naming it here trips TS2589.
|
|
94
|
+
*/
|
|
95
|
+
function makeUpdateBy(
|
|
96
|
+
data: Partial<WorkflowVariable>,
|
|
97
|
+
props?: Record<string, unknown> | undefined,
|
|
98
|
+
): UpdateBy<WorkflowVariable> {
|
|
99
|
+
return {
|
|
100
|
+
query: { _id: VARIABLE_ID.toString() },
|
|
101
|
+
data: data,
|
|
102
|
+
limit: 1,
|
|
103
|
+
skip: 0,
|
|
104
|
+
props: props || { isRoot: true },
|
|
105
|
+
} as unknown as UpdateBy<WorkflowVariable>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/*
|
|
109
|
+
* Stub the two reads the hook makes. findBy answers "which rows does this
|
|
110
|
+
* update touch"; countBy answers "does the new name already exist in that row's
|
|
111
|
+
* scope". Both calls are recorded WHOLE - query, select and props - because
|
|
112
|
+
* every assertion worth making here is about what was asked for rather than
|
|
113
|
+
* about what a stub chose to answer.
|
|
114
|
+
*/
|
|
115
|
+
type RecordedCall = {
|
|
116
|
+
query: Record<string, unknown>;
|
|
117
|
+
select?: Record<string, unknown> | undefined;
|
|
118
|
+
props?: Record<string, unknown> | undefined;
|
|
119
|
+
limit?: unknown;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
function stubReads(options: {
|
|
123
|
+
itemsBeingUpdated: Array<WorkflowVariable>;
|
|
124
|
+
conflictCount: number;
|
|
125
|
+
}): { countByCalls: Array<RecordedCall>; findByCalls: Array<RecordedCall> } {
|
|
126
|
+
const countByCalls: Array<RecordedCall> = [];
|
|
127
|
+
const findByCalls: Array<RecordedCall> = [];
|
|
128
|
+
|
|
129
|
+
function record(call: unknown): RecordedCall {
|
|
130
|
+
const typed: RecordedCall = call as RecordedCall;
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
query: typed.query,
|
|
134
|
+
select: typed.select,
|
|
135
|
+
props: typed.props,
|
|
136
|
+
limit: typed.limit,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
jest
|
|
141
|
+
.spyOn(WorkflowVariableService, "findBy")
|
|
142
|
+
.mockImplementation(
|
|
143
|
+
async (findBy: unknown): Promise<Array<WorkflowVariable>> => {
|
|
144
|
+
findByCalls.push(record(findBy));
|
|
145
|
+
return options.itemsBeingUpdated;
|
|
146
|
+
},
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
jest
|
|
150
|
+
.spyOn(WorkflowVariableService, "countBy")
|
|
151
|
+
.mockImplementation(async (countBy: unknown): Promise<PositiveNumber> => {
|
|
152
|
+
countByCalls.push(record(countBy));
|
|
153
|
+
return new PositiveNumber(options.conflictCount);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
return { countByCalls, findByCalls };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/*
|
|
160
|
+
* QueryHelper builds TypeORM Raw() operators, so a query value is a
|
|
161
|
+
* FindOperator carrying the SQL fragment it will emit and the parameter bound
|
|
162
|
+
* into it. Asserting "it is defined" would accept the exact inversion of every
|
|
163
|
+
* one of these predicates, so the tests below read the operator instead.
|
|
164
|
+
*/
|
|
165
|
+
type RawOperator = {
|
|
166
|
+
type?: string | undefined;
|
|
167
|
+
getSql?: ((alias: string) => string) | undefined;
|
|
168
|
+
objectLiteralParameters?: Record<string, unknown> | undefined;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
function sqlOf(value: unknown, alias: string): string {
|
|
172
|
+
const operator: RawOperator = value as RawOperator;
|
|
173
|
+
|
|
174
|
+
if (!operator || typeof operator.getSql !== "function") {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`Expected a Raw() operator for "${alias}", got ${JSON.stringify(value)}`,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return operator.getSql(alias).replace(/\s+/g, " ");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function paramsOf(value: unknown): Array<unknown> {
|
|
184
|
+
const operator: RawOperator = value as RawOperator;
|
|
185
|
+
|
|
186
|
+
return Object.values(operator?.objectLiteralParameters || {});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
describe("WorkflowVariableService rename uniqueness", () => {
|
|
190
|
+
afterEach(() => {
|
|
191
|
+
jest.restoreAllMocks();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe("updates that are not renames", () => {
|
|
195
|
+
/*
|
|
196
|
+
* The overwhelmingly common update from the dashboard edit form carries no
|
|
197
|
+
* name at all, or carries only content through the "Update Content" modal.
|
|
198
|
+
* Neither should cost a round trip.
|
|
199
|
+
*/
|
|
200
|
+
test("a content-only update reads nothing and is allowed through", async () => {
|
|
201
|
+
const { countByCalls } = stubReads({
|
|
202
|
+
itemsBeingUpdated: [],
|
|
203
|
+
conflictCount: 99,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const result: OnUpdate<WorkflowVariable> = await hook()(
|
|
207
|
+
makeUpdateBy({ content: "rotated-token" }),
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
expect(
|
|
211
|
+
(result.updateBy.data as unknown as Partial<WorkflowVariable>).content,
|
|
212
|
+
).toBe("rotated-token");
|
|
213
|
+
expect(countByCalls).toHaveLength(0);
|
|
214
|
+
expect(WorkflowVariableService.findBy).not.toHaveBeenCalled();
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test("a description-and-secret update is allowed through", async () => {
|
|
218
|
+
stubReads({ itemsBeingUpdated: [], conflictCount: 99 });
|
|
219
|
+
|
|
220
|
+
await expect(
|
|
221
|
+
hook()(
|
|
222
|
+
makeUpdateBy({
|
|
223
|
+
description: "Token for the nightly Airflow sync",
|
|
224
|
+
isSecret: "true",
|
|
225
|
+
} as Partial<WorkflowVariable>),
|
|
226
|
+
),
|
|
227
|
+
).resolves.toBeDefined();
|
|
228
|
+
|
|
229
|
+
expect(WorkflowVariableService.findBy).not.toHaveBeenCalled();
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
describe("renames", () => {
|
|
234
|
+
test("allows a rename when nothing else holds the new name", async () => {
|
|
235
|
+
stubReads({
|
|
236
|
+
itemsBeingUpdated: [
|
|
237
|
+
makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
|
|
238
|
+
],
|
|
239
|
+
conflictCount: 0,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const result: OnUpdate<WorkflowVariable> = await hook()(
|
|
243
|
+
makeUpdateBy({ name: "NewName" }),
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
expect(
|
|
247
|
+
(result.updateBy.data as unknown as Partial<WorkflowVariable>).name,
|
|
248
|
+
).toBe("NewName");
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test("refuses a rename onto a name that already exists on the same workflow", async () => {
|
|
252
|
+
stubReads({
|
|
253
|
+
itemsBeingUpdated: [
|
|
254
|
+
makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
|
|
255
|
+
],
|
|
256
|
+
conflictCount: 1,
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
await expect(hook()(makeUpdateBy({ name: "Taken" }))).rejects.toThrow(
|
|
260
|
+
BadDataException,
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
await expect(hook()(makeUpdateBy({ name: "Taken" }))).rejects.toThrow(
|
|
264
|
+
/already exists on this workflow/,
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
/*
|
|
269
|
+
* The two namespaces get different wording because they are reached from
|
|
270
|
+
* different pages. A global-variable collision that says "on this workflow"
|
|
271
|
+
* sends the reader looking at a workflow they never opened.
|
|
272
|
+
*/
|
|
273
|
+
test("names the global namespace when the row is a global variable", async () => {
|
|
274
|
+
stubReads({
|
|
275
|
+
itemsBeingUpdated: [makeVariable({ name: "OldName" })],
|
|
276
|
+
conflictCount: 1,
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
await expect(hook()(makeUpdateBy({ name: "Taken" }))).rejects.toThrow(
|
|
280
|
+
/global variable named "Taken" already exists in this project/,
|
|
281
|
+
);
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
describe("which rows the guard inspects", () => {
|
|
286
|
+
/*
|
|
287
|
+
* The hook resolves the update's own query to real rows before it can judge
|
|
288
|
+
* anything, and every part of that read matters: the query decides which
|
|
289
|
+
* rows, isRoot lets it see rows the caller cannot read, the select supplies
|
|
290
|
+
* the scope the lookup is built from, and the limit is what lets the
|
|
291
|
+
* multi-row guard below see all of them. A stub that answers regardless of
|
|
292
|
+
* its arguments would hide all four.
|
|
293
|
+
*/
|
|
294
|
+
test("reads exactly the rows this update targets, as root, with the scope columns", async () => {
|
|
295
|
+
const { findByCalls } = stubReads({
|
|
296
|
+
itemsBeingUpdated: [
|
|
297
|
+
makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
|
|
298
|
+
],
|
|
299
|
+
conflictCount: 0,
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
await hook()(makeUpdateBy({ name: "NewName" }));
|
|
303
|
+
|
|
304
|
+
expect(findByCalls).toHaveLength(1);
|
|
305
|
+
|
|
306
|
+
const call: RecordedCall = findByCalls[0]!;
|
|
307
|
+
|
|
308
|
+
expect(call.query).toEqual({ _id: VARIABLE_ID.toString() });
|
|
309
|
+
expect(call.props).toEqual({ isRoot: true });
|
|
310
|
+
expect(call.props).not.toHaveProperty("userId");
|
|
311
|
+
expect(call.select).toEqual(
|
|
312
|
+
expect.objectContaining({
|
|
313
|
+
_id: true,
|
|
314
|
+
name: true,
|
|
315
|
+
projectId: true,
|
|
316
|
+
workflowId: true,
|
|
317
|
+
}),
|
|
318
|
+
);
|
|
319
|
+
expect(call.limit).toBe(LIMIT_PER_PROJECT);
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
describe("the scope the conflict is looked up in", () => {
|
|
324
|
+
test("a workflow-local rename is checked against that workflow only", async () => {
|
|
325
|
+
const { countByCalls } = stubReads({
|
|
326
|
+
itemsBeingUpdated: [
|
|
327
|
+
makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
|
|
328
|
+
],
|
|
329
|
+
conflictCount: 0,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
await hook()(makeUpdateBy({ name: "NewName" }));
|
|
333
|
+
|
|
334
|
+
expect(countByCalls).toHaveLength(1);
|
|
335
|
+
|
|
336
|
+
const call: RecordedCall = countByCalls[0]!;
|
|
337
|
+
const query: Record<string, unknown> = call.query;
|
|
338
|
+
|
|
339
|
+
expect(query["projectId"]).toBe(PROJECT_ID);
|
|
340
|
+
expect(query["workflowId"]).toBe(WORKFLOW_ID);
|
|
341
|
+
|
|
342
|
+
/*
|
|
343
|
+
* As root: the conflicting row can easily be one the caller cannot read -
|
|
344
|
+
* read access is permission- and label-gated - and a count that cannot
|
|
345
|
+
* see it reports zero and waves the duplicate through.
|
|
346
|
+
*/
|
|
347
|
+
expect(call.props).toEqual({ isRoot: true });
|
|
348
|
+
|
|
349
|
+
/*
|
|
350
|
+
* The row must be excluded from its own lookup. Asserting the operator
|
|
351
|
+
* rather than its presence, because `equalTo` would also be "defined" -
|
|
352
|
+
* and would make the row collide with itself, refusing every rename.
|
|
353
|
+
*/
|
|
354
|
+
expect(sqlOf(query["_id"], "_id")).toContain("!=");
|
|
355
|
+
expect(paramsOf(query["_id"])).toContain(VARIABLE_ID.toString());
|
|
356
|
+
|
|
357
|
+
/*
|
|
358
|
+
* Case-insensitive, on the NEW name. A lookup built from the old name
|
|
359
|
+
* asks "does anything else already have my current name", answers no, and
|
|
360
|
+
* lets the rename land on top of an existing variable.
|
|
361
|
+
*/
|
|
362
|
+
expect(sqlOf(query["name"], "name")).toContain("LOWER");
|
|
363
|
+
expect(paramsOf(query["name"])).toContain("newname");
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
/*
|
|
367
|
+
* Global variables are the rows whose workflowId is null, and they share a
|
|
368
|
+
* namespace of their own. Passing `workflowId: undefined` would drop the
|
|
369
|
+
* clause altogether and compare a global variable against every
|
|
370
|
+
* workflow-local variable in the project - which would reject renames that
|
|
371
|
+
* are perfectly legal, and is exactly the shape of bug that makes people
|
|
372
|
+
* give up and go back to delete-and-recreate. IS NOT NULL would do the same
|
|
373
|
+
* thing, which is why the SQL is read rather than merely required to exist.
|
|
374
|
+
*/
|
|
375
|
+
test("a global rename is checked against the project's global variables, not every workflow's", async () => {
|
|
376
|
+
const { countByCalls } = stubReads({
|
|
377
|
+
itemsBeingUpdated: [makeVariable({ name: "OldName" })],
|
|
378
|
+
conflictCount: 0,
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
await hook()(makeUpdateBy({ name: "NewName" }));
|
|
382
|
+
|
|
383
|
+
expect(countByCalls).toHaveLength(1);
|
|
384
|
+
|
|
385
|
+
const query: Record<string, unknown> = countByCalls[0]!.query;
|
|
386
|
+
|
|
387
|
+
expect(query["projectId"]).toBe(PROJECT_ID);
|
|
388
|
+
|
|
389
|
+
const workflowSql: string = sqlOf(query["workflowId"], "workflowId");
|
|
390
|
+
|
|
391
|
+
expect(workflowSql).toContain("IS NULL");
|
|
392
|
+
expect(workflowSql).not.toContain("IS NOT NULL");
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
/*
|
|
396
|
+
* The count must run as root whoever is calling. Asserting that against a
|
|
397
|
+
* root fixture proves nothing - `props: updateBy.props` is indistinguishable
|
|
398
|
+
* from `props: { isRoot: true }` when the caller already is root - so this
|
|
399
|
+
* one calls as an ordinary user and checks the lookup did NOT inherit those
|
|
400
|
+
* props. It matters because the conflicting row can be one the caller
|
|
401
|
+
* cannot read: read access is label-gated, and a count that cannot see the
|
|
402
|
+
* duplicate reports zero and waves it through.
|
|
403
|
+
*/
|
|
404
|
+
test("counts as root even when the caller is not", async () => {
|
|
405
|
+
const { countByCalls } = stubReads({
|
|
406
|
+
itemsBeingUpdated: [
|
|
407
|
+
makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
|
|
408
|
+
],
|
|
409
|
+
conflictCount: 0,
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
await hook()(
|
|
413
|
+
makeUpdateBy(
|
|
414
|
+
{ name: "NewName" },
|
|
415
|
+
{ userId: USER_ID, tenantId: PROJECT_ID },
|
|
416
|
+
),
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
expect(countByCalls).toHaveLength(1);
|
|
420
|
+
expect(countByCalls[0]!.props).toEqual({ isRoot: true });
|
|
421
|
+
expect(countByCalls[0]!.props).not.toHaveProperty("userId");
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
test("the row's own project scopes the lookup, not the caller's", async () => {
|
|
425
|
+
const { countByCalls } = stubReads({
|
|
426
|
+
itemsBeingUpdated: [
|
|
427
|
+
makeVariable({ name: "OldName", projectId: OTHER_PROJECT_ID }),
|
|
428
|
+
],
|
|
429
|
+
conflictCount: 0,
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
await hook()(makeUpdateBy({ name: "NewName" }));
|
|
433
|
+
|
|
434
|
+
expect(countByCalls[0]!.query["projectId"]).toBe(OTHER_PROJECT_ID);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
/*
|
|
438
|
+
* projectId is non-nullable on the table, so a row without one means the
|
|
439
|
+
* select or the row is wrong. Dropping the clause would count the name
|
|
440
|
+
* across every project on the instance and refuse legitimate renames, so
|
|
441
|
+
* the guard refuses rather than answering the wrong question.
|
|
442
|
+
*/
|
|
443
|
+
test("refuses rather than issuing an unscoped lookup when the row has no project", async () => {
|
|
444
|
+
const orphan: WorkflowVariable = makeVariable({ name: "OldName" });
|
|
445
|
+
delete orphan.projectId;
|
|
446
|
+
|
|
447
|
+
const { countByCalls } = stubReads({
|
|
448
|
+
itemsBeingUpdated: [orphan],
|
|
449
|
+
conflictCount: 0,
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
await expect(hook()(makeUpdateBy({ name: "NewName" }))).rejects.toThrow(
|
|
453
|
+
BadDataException,
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
expect(countByCalls).toHaveLength(0);
|
|
457
|
+
});
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
describe("renames that are not really renames", () => {
|
|
461
|
+
/*
|
|
462
|
+
* Saving the edit form without touching the name resubmits the name it
|
|
463
|
+
* already has. That must not be reported as a collision with itself - and
|
|
464
|
+
* it does not even need the lookup.
|
|
465
|
+
*/
|
|
466
|
+
test("re-submitting the same name costs nothing and is allowed", async () => {
|
|
467
|
+
const { countByCalls } = stubReads({
|
|
468
|
+
itemsBeingUpdated: [
|
|
469
|
+
makeVariable({ name: "SameName", workflowId: WORKFLOW_ID }),
|
|
470
|
+
],
|
|
471
|
+
conflictCount: 1,
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
await expect(
|
|
475
|
+
hook()(makeUpdateBy({ name: "SameName" })),
|
|
476
|
+
).resolves.toBeDefined();
|
|
477
|
+
|
|
478
|
+
expect(countByCalls).toHaveLength(0);
|
|
479
|
+
|
|
480
|
+
/*
|
|
481
|
+
* The zero above is only meaningful next to a one: a hook that had been
|
|
482
|
+
* deleted outright would also never call countBy. A genuine rename
|
|
483
|
+
* through the same stubs proves the short-circuit is a short-circuit
|
|
484
|
+
* rather than an absence.
|
|
485
|
+
*/
|
|
486
|
+
await expect(
|
|
487
|
+
hook()(makeUpdateBy({ name: "GenuinelyDifferent" })),
|
|
488
|
+
).rejects.toThrow(BadDataException);
|
|
489
|
+
|
|
490
|
+
expect(countByCalls).toHaveLength(1);
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
test("changing only the casing of the row's own name is allowed", async () => {
|
|
494
|
+
const { countByCalls } = stubReads({
|
|
495
|
+
itemsBeingUpdated: [
|
|
496
|
+
makeVariable({ name: "apitoken", workflowId: WORKFLOW_ID }),
|
|
497
|
+
],
|
|
498
|
+
conflictCount: 1,
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
/*
|
|
502
|
+
* The uniqueness lookup is case-insensitive (QueryHelper.findWithSameText
|
|
503
|
+
* lowercases both sides), so "apitoken" -> "APIToken" is the same row
|
|
504
|
+
* changing how it is spelled, not a collision. Without the guard this
|
|
505
|
+
* would count itself and refuse.
|
|
506
|
+
*/
|
|
507
|
+
await expect(
|
|
508
|
+
hook()(makeUpdateBy({ name: "APIToken" })),
|
|
509
|
+
).resolves.toBeDefined();
|
|
510
|
+
|
|
511
|
+
expect(countByCalls).toHaveLength(0);
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
/*
|
|
515
|
+
* The other half of case-insensitivity, and the one that matters more: a
|
|
516
|
+
* DIFFERENT row already holding the name in another case is a real
|
|
517
|
+
* collision, because the lookup lowercases both sides. The short-circuit
|
|
518
|
+
* above must not swallow it.
|
|
519
|
+
*/
|
|
520
|
+
test("still refuses a rename that collides with another row only by casing", async () => {
|
|
521
|
+
const { countByCalls } = stubReads({
|
|
522
|
+
itemsBeingUpdated: [
|
|
523
|
+
makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
|
|
524
|
+
],
|
|
525
|
+
conflictCount: 1,
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
await expect(hook()(makeUpdateBy({ name: "APIToken" }))).rejects.toThrow(
|
|
529
|
+
/already exists on this workflow/,
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
expect(paramsOf(countByCalls[0]!.query["name"])).toContain("apitoken");
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
/*
|
|
536
|
+
* A blank name is a write to the column, not the absence of one. Two rows
|
|
537
|
+
* blanked in the same workflow would both become "" and collide like any
|
|
538
|
+
* other duplicate, so the guard has to run rather than treat it as "no
|
|
539
|
+
* rename".
|
|
540
|
+
*/
|
|
541
|
+
test("treats a blanked name as a rename rather than skipping the guard", async () => {
|
|
542
|
+
const { countByCalls } = stubReads({
|
|
543
|
+
itemsBeingUpdated: [
|
|
544
|
+
makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
|
|
545
|
+
],
|
|
546
|
+
conflictCount: 1,
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
await expect(hook()(makeUpdateBy({ name: "" }))).rejects.toThrow(
|
|
550
|
+
BadDataException,
|
|
551
|
+
);
|
|
552
|
+
|
|
553
|
+
expect(countByCalls).toHaveLength(1);
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
/*
|
|
557
|
+
* An update that does not carry the column at all IS exempt, and must stay
|
|
558
|
+
* so - that is every content-only and description-only save.
|
|
559
|
+
*/
|
|
560
|
+
test("an update carrying no name at all still skips the guard", async () => {
|
|
561
|
+
const { findByCalls } = stubReads({
|
|
562
|
+
itemsBeingUpdated: [
|
|
563
|
+
makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
|
|
564
|
+
],
|
|
565
|
+
conflictCount: 1,
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
await expect(
|
|
569
|
+
hook()(makeUpdateBy({ description: "Just a note" })),
|
|
570
|
+
).resolves.toBeDefined();
|
|
571
|
+
|
|
572
|
+
expect(findByCalls).toHaveLength(0);
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
/*
|
|
577
|
+
* _updateBy calls this hook BEFORE ModelPermission.checkUpdateQueryPermissions,
|
|
578
|
+
* which is the step that appends the project clause. A hook reading
|
|
579
|
+
* unscoped-as-root would therefore answer questions about another project's
|
|
580
|
+
* rows - and its refusal messages say whether a variable is global and
|
|
581
|
+
* whether a name is taken there - before any authorization had run. So the
|
|
582
|
+
* hook applies the tenant scope itself.
|
|
583
|
+
*/
|
|
584
|
+
describe("tenant scoping, which the permission layer has not applied yet", () => {
|
|
585
|
+
test("narrows the lookup to the calling project", async () => {
|
|
586
|
+
const { findByCalls } = stubReads({
|
|
587
|
+
itemsBeingUpdated: [],
|
|
588
|
+
conflictCount: 0,
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
await hook()(
|
|
592
|
+
makeUpdateBy(
|
|
593
|
+
{ name: "NewName" },
|
|
594
|
+
{ userId: USER_ID, tenantId: PROJECT_ID },
|
|
595
|
+
),
|
|
596
|
+
);
|
|
597
|
+
|
|
598
|
+
expect(findByCalls[0]!.query).toEqual({
|
|
599
|
+
_id: VARIABLE_ID.toString(),
|
|
600
|
+
projectId: PROJECT_ID,
|
|
601
|
+
});
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
/*
|
|
605
|
+
* The oracle this closes: a variable id belonging to a project the caller
|
|
606
|
+
* cannot see resolves to no rows, so the hook says nothing at all and the
|
|
607
|
+
* permission layer refuses the update on its own terms.
|
|
608
|
+
*/
|
|
609
|
+
test("says nothing about a row outside the calling project", async () => {
|
|
610
|
+
const { countByCalls } = stubReads({
|
|
611
|
+
itemsBeingUpdated: [],
|
|
612
|
+
conflictCount: 1,
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
await expect(
|
|
616
|
+
hook()(
|
|
617
|
+
makeUpdateBy(
|
|
618
|
+
{ name: "STRIPE_SECRET_KEY" },
|
|
619
|
+
{ userId: USER_ID, tenantId: OTHER_PROJECT_ID },
|
|
620
|
+
),
|
|
621
|
+
),
|
|
622
|
+
).resolves.toBeDefined();
|
|
623
|
+
|
|
624
|
+
expect(countByCalls).toHaveLength(0);
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
/*
|
|
628
|
+
* Internal callers run as root with no tenant. Scoping those to a tenant
|
|
629
|
+
* they do not have would silently stop the guard from working at all.
|
|
630
|
+
*/
|
|
631
|
+
test("leaves a root call with no tenant unscoped", async () => {
|
|
632
|
+
const { findByCalls } = stubReads({
|
|
633
|
+
itemsBeingUpdated: [],
|
|
634
|
+
conflictCount: 0,
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
await hook()(makeUpdateBy({ name: "NewName" }));
|
|
638
|
+
|
|
639
|
+
expect(findByCalls[0]!.query).toEqual({ _id: VARIABLE_ID.toString() });
|
|
640
|
+
});
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
/*
|
|
644
|
+
* isSecret is a one-way flag, and the service is the only place that can say
|
|
645
|
+
* so - a ColumnAccessControl list cannot express "you may set this but not
|
|
646
|
+
* clear it".
|
|
647
|
+
*
|
|
648
|
+
* Clearing it is the direction that exposes something. `content` is
|
|
649
|
+
* unreadable through the API by anyone, and this flag is what keeps its value
|
|
650
|
+
* out of the run logs - so a caller who may write a variable but not read it
|
|
651
|
+
* could otherwise clear the flag, trigger a run, and read the value out of a
|
|
652
|
+
* log it had been redacted from.
|
|
653
|
+
*/
|
|
654
|
+
describe("the secret flag is a ratchet", () => {
|
|
655
|
+
test("lets a variable be marked secret", async () => {
|
|
656
|
+
stubReads({
|
|
657
|
+
itemsBeingUpdated: [
|
|
658
|
+
makeVariable({ name: "Token", workflowId: WORKFLOW_ID }),
|
|
659
|
+
],
|
|
660
|
+
conflictCount: 0,
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
await expect(
|
|
664
|
+
hook()(makeUpdateBy({ isSecret: "true" } as Partial<WorkflowVariable>)),
|
|
665
|
+
).resolves.toBeDefined();
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
test("refuses to un-mark a variable that is secret", async () => {
|
|
669
|
+
stubReads({
|
|
670
|
+
itemsBeingUpdated: [
|
|
671
|
+
makeVariable({
|
|
672
|
+
name: "Token",
|
|
673
|
+
workflowId: WORKFLOW_ID,
|
|
674
|
+
isSecret: true,
|
|
675
|
+
}),
|
|
676
|
+
],
|
|
677
|
+
conflictCount: 0,
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
await expect(
|
|
681
|
+
hook()(
|
|
682
|
+
makeUpdateBy({ isSecret: "false" } as Partial<WorkflowVariable>),
|
|
683
|
+
),
|
|
684
|
+
).rejects.toThrow(BadDataException);
|
|
685
|
+
|
|
686
|
+
await expect(
|
|
687
|
+
hook()(
|
|
688
|
+
makeUpdateBy({
|
|
689
|
+
isSecret: false,
|
|
690
|
+
} as unknown as Partial<WorkflowVariable>),
|
|
691
|
+
),
|
|
692
|
+
).rejects.toThrow(/cannot be un-marked/);
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
/*
|
|
696
|
+
* The flag comes back from Postgres as a real boolean and can arrive from a
|
|
697
|
+
* request body as the string "true". RunWorkflow reads it exactly this way
|
|
698
|
+
* (getSecretWorkflowVariableValues), and a guard that disagreed with the
|
|
699
|
+
* redaction it protects would be worse than no guard.
|
|
700
|
+
*/
|
|
701
|
+
test("reads the string form of the flag the way the run logs do", async () => {
|
|
702
|
+
stubReads({
|
|
703
|
+
itemsBeingUpdated: [
|
|
704
|
+
makeVariable({
|
|
705
|
+
name: "Token",
|
|
706
|
+
workflowId: WORKFLOW_ID,
|
|
707
|
+
isSecret: "true",
|
|
708
|
+
}),
|
|
709
|
+
],
|
|
710
|
+
conflictCount: 0,
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
await expect(
|
|
714
|
+
hook()(
|
|
715
|
+
makeUpdateBy({
|
|
716
|
+
isSecret: false,
|
|
717
|
+
} as unknown as Partial<WorkflowVariable>),
|
|
718
|
+
),
|
|
719
|
+
).rejects.toThrow(BadDataException);
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
test("leaves a variable that was never secret alone", async () => {
|
|
723
|
+
stubReads({
|
|
724
|
+
itemsBeingUpdated: [
|
|
725
|
+
makeVariable({
|
|
726
|
+
name: "Token",
|
|
727
|
+
workflowId: WORKFLOW_ID,
|
|
728
|
+
isSecret: false,
|
|
729
|
+
}),
|
|
730
|
+
],
|
|
731
|
+
conflictCount: 0,
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
await expect(
|
|
735
|
+
hook()(
|
|
736
|
+
makeUpdateBy({ isSecret: "false" } as Partial<WorkflowVariable>),
|
|
737
|
+
),
|
|
738
|
+
).resolves.toBeDefined();
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
test("an update that does not mention the flag reads nothing", async () => {
|
|
742
|
+
const { findByCalls } = stubReads({
|
|
743
|
+
itemsBeingUpdated: [
|
|
744
|
+
makeVariable({
|
|
745
|
+
name: "Token",
|
|
746
|
+
workflowId: WORKFLOW_ID,
|
|
747
|
+
isSecret: true,
|
|
748
|
+
}),
|
|
749
|
+
],
|
|
750
|
+
conflictCount: 0,
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
await expect(
|
|
754
|
+
hook()(makeUpdateBy({ content: "rotated-token" })),
|
|
755
|
+
).resolves.toBeDefined();
|
|
756
|
+
|
|
757
|
+
expect(findByCalls).toHaveLength(0);
|
|
758
|
+
});
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
/*
|
|
762
|
+
* sanitizeUpdateData passes plain objects straight through, so `name` is
|
|
763
|
+
* whatever the request body said it was. Without the type check this reached
|
|
764
|
+
* newName.toLowerCase() and became a 500 with a stack trace rather than a 400
|
|
765
|
+
* naming the field.
|
|
766
|
+
*/
|
|
767
|
+
describe("a name that is not text", () => {
|
|
768
|
+
test("is refused as bad data rather than crashing the request", async () => {
|
|
769
|
+
const { findByCalls } = stubReads({
|
|
770
|
+
itemsBeingUpdated: [
|
|
771
|
+
makeVariable({ name: "OldName", workflowId: WORKFLOW_ID }),
|
|
772
|
+
],
|
|
773
|
+
conflictCount: 0,
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
await expect(
|
|
777
|
+
hook()(
|
|
778
|
+
makeUpdateBy({
|
|
779
|
+
name: { $ne: null },
|
|
780
|
+
} as unknown as Partial<WorkflowVariable>),
|
|
781
|
+
),
|
|
782
|
+
).rejects.toThrow(BadDataException);
|
|
783
|
+
|
|
784
|
+
await expect(
|
|
785
|
+
hook()(
|
|
786
|
+
makeUpdateBy({ name: 42 } as unknown as Partial<WorkflowVariable>),
|
|
787
|
+
),
|
|
788
|
+
).rejects.toThrow(/must be text/);
|
|
789
|
+
|
|
790
|
+
expect(findByCalls).toHaveLength(0);
|
|
791
|
+
});
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
describe("multi-row updates", () => {
|
|
795
|
+
/*
|
|
796
|
+
* The dashboard always sends a single _id, but the CRUD API accepts a
|
|
797
|
+
* broader query. Renaming two rows to one name is a collision the database
|
|
798
|
+
* lookup cannot see: neither row conflicts with anything that exists yet,
|
|
799
|
+
* they conflict with each other once both are written.
|
|
800
|
+
*/
|
|
801
|
+
test("refuses to rename more than one variable to the same name at once", async () => {
|
|
802
|
+
const { countByCalls } = stubReads({
|
|
803
|
+
itemsBeingUpdated: [
|
|
804
|
+
makeVariable({
|
|
805
|
+
id: VARIABLE_ID,
|
|
806
|
+
name: "First",
|
|
807
|
+
workflowId: WORKFLOW_ID,
|
|
808
|
+
}),
|
|
809
|
+
makeVariable({
|
|
810
|
+
id: OTHER_VARIABLE_ID,
|
|
811
|
+
name: "Second",
|
|
812
|
+
workflowId: WORKFLOW_ID,
|
|
813
|
+
}),
|
|
814
|
+
],
|
|
815
|
+
conflictCount: 0,
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
await expect(hook()(makeUpdateBy({ name: "Merged" }))).rejects.toThrow(
|
|
819
|
+
BadDataException,
|
|
820
|
+
);
|
|
821
|
+
|
|
822
|
+
await expect(hook()(makeUpdateBy({ name: "Merged" }))).rejects.toThrow(
|
|
823
|
+
/Cannot rename 2 workflow variables/,
|
|
824
|
+
);
|
|
825
|
+
|
|
826
|
+
expect(countByCalls).toHaveLength(0);
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
/*
|
|
830
|
+
* A rename whose query matches nothing is a no-op update, not a conflict.
|
|
831
|
+
* Throwing here would turn "the row was already deleted" into a confusing
|
|
832
|
+
* uniqueness error.
|
|
833
|
+
*/
|
|
834
|
+
test("allows a rename whose query matches no rows", async () => {
|
|
835
|
+
stubReads({ itemsBeingUpdated: [], conflictCount: 0 });
|
|
836
|
+
|
|
837
|
+
await expect(
|
|
838
|
+
hook()(makeUpdateBy({ name: "NewName" })),
|
|
839
|
+
).resolves.toBeDefined();
|
|
840
|
+
});
|
|
841
|
+
});
|
|
842
|
+
});
|