@oneuptime/common 14.0.7 → 14.0.8
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/Incident.ts +267 -1
- package/Models/DatabaseModels/IncidentCustomField.ts +202 -0
- package/Models/DatabaseModels/IncidentEpisode.ts +30 -0
- package/Models/DatabaseModels/IncidentTemplate.ts +126 -1
- package/Models/DatabaseModels/StatusPage.ts +55 -0
- package/Models/DatabaseModels/StatusPageSubscriber.ts +128 -0
- package/Server/API/IncidentAPI.ts +162 -0
- package/Server/API/StatusPageAPI.ts +487 -171
- package/Server/API/StatusPageSubscriberAPI.ts +63 -15
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.ts +108 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.ts +168 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.ts +44 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
- package/Server/Infrastructure/Semaphore.ts +10 -0
- package/Server/Middleware/IdentityRateLimit.ts +108 -3
- package/Server/Middleware/SubscriberNotificationPreviewRateLimit.ts +237 -0
- package/Server/Middleware/SubscriberNotificationTestSendRateLimit.ts +304 -0
- package/Server/Services/DatabaseService.ts +93 -10
- package/Server/Services/IncidentCustomFieldService.ts +276 -1
- package/Server/Services/IncidentEpisodePublicNoteService.ts +28 -0
- package/Server/Services/IncidentEpisodeService.ts +15 -0
- package/Server/Services/IncidentEpisodeStateTimelineService.ts +27 -1
- package/Server/Services/IncidentPublicNoteService.ts +30 -1
- package/Server/Services/IncidentService.ts +1535 -65
- package/Server/Services/IncidentStateTimelineService.ts +13 -0
- package/Server/Services/IncidentTemplateService.ts +109 -0
- package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
- package/Server/Services/ScheduledMaintenanceService.ts +68 -18
- package/Server/Services/SmsService.ts +10 -0
- package/Server/Services/StatusPageService.ts +65 -8
- package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +299 -37
- package/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.ts +129 -0
- package/Server/Services/StatusPageSubscriberService.ts +1161 -64
- package/Server/Types/Markdown.ts +153 -6
- package/Server/Types/Workflow/Components/Email.ts +61 -2
- package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
- package/Server/Utils/DataSource/EgressGuard.ts +66 -21
- package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -0
- package/Server/Utils/SSRFProtection.ts +76 -16
- package/Server/Utils/StatusPage/IncidentStatusPageScope.ts +948 -0
- package/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.ts +656 -0
- package/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.ts +805 -0
- package/Server/Utils/StatusPage/StatusPageExclusion.ts +18 -0
- package/Server/Utils/StatusPage/StatusPageReadAccess.ts +125 -0
- package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.ts +151 -0
- package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.ts +70 -0
- package/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.ts +421 -0
- package/Server/Utils/StatusPage/SubscriberNotificationClaim.ts +107 -0
- package/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.ts +1049 -0
- package/Server/Utils/StatusPage/SubscriberNotificationFanOut.ts +180 -0
- package/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.ts +839 -0
- package/Server/Utils/StatusPage/SubscriberNotificationResendAccess.ts +393 -0
- package/Server/Utils/StatusPage/SubscriberNotificationRunLimit.ts +246 -0
- package/Server/Utils/StatusPage/SubscriberNotificationTiming.ts +133 -0
- package/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.ts +215 -0
- package/Server/Utils/StatusPageResource.ts +51 -20
- package/Server/Utils/VM/VMAPI.ts +1 -0
- package/Server/Utils/VM/VMRunner.ts +10 -0
- package/Server/Utils/Workflow/OAuth2TokenClient.ts +10 -0
- package/Server/Views/Partials/SensitiveUrlToken.ejs +8 -5
- package/Tests/App/Accounts/RegisterVerifyEmail.test.tsx +748 -0
- package/Tests/App/Accounts/ResendVerificationEmail.test.tsx +1222 -0
- package/Tests/App/Accounts/VerificationEmailResendUtils.test.ts +797 -0
- package/Tests/App/Accounts/VerifyEmailPending.test.tsx +538 -0
- package/Tests/App/Accounts/VerifyEmailResend.test.tsx +779 -0
- package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +357 -0
- package/Tests/App/Dashboard/EventNotes.test.tsx +776 -0
- package/Tests/App/Dashboard/EventNotesPages.test.tsx +119 -0
- package/Tests/App/Dashboard/EventNotesUtil.test.ts +116 -17
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +242 -5
- package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
- package/Tests/App/Dashboard/IncidentCreateDetailsStep.test.tsx +643 -0
- package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +8 -1
- package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +601 -0
- package/Tests/App/Dashboard/IncidentCustomFieldTemplateVariables.test.tsx +386 -0
- package/Tests/App/Dashboard/IncidentNoteTemplatePlaceholders.test.tsx +124 -0
- package/Tests/App/Dashboard/IncidentNoteTemplateVariablesLoader.test.ts +305 -0
- package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +112 -0
- package/Tests/App/Dashboard/IncidentSettingsRenotifyOnPublish.test.tsx +674 -0
- package/Tests/App/Dashboard/IncidentSettingsStatusPageScope.test.tsx +1051 -0
- package/Tests/App/Dashboard/IncidentTemplateCustomFields.test.tsx +384 -0
- package/Tests/App/Dashboard/IncidentTemplateStatusPageScopeCard.test.tsx +215 -0
- package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +113 -1
- package/Tests/App/Dashboard/SubscriberAudienceSummary.test.tsx +512 -0
- package/Tests/App/Dashboard/SubscriberNotificationPreviewModal.test.tsx +837 -0
- package/Tests/App/Dashboard/SubscriberNotificationStatusLabel.test.tsx +88 -0
- package/Tests/App/Dashboard/SubscriberNotificationStatusResend.test.tsx +473 -0
- package/Tests/App/Dashboard/SubscriberTemplateLivePreview.test.tsx +196 -0
- package/Tests/App/Dashboard/TeamAddedSubscribersUnsubscribedNotice.test.tsx +248 -0
- package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +64 -3
- package/Tests/App/StatusPage/StatusPageUnsubscribePage.test.tsx +412 -0
- package/Tests/Models/IncidentCustomFieldApiSchemaContract.test.ts +217 -0
- package/Tests/Models/IncidentCustomFieldCreateSettingsColumns.test.ts +252 -0
- package/Tests/Models/StatusPageSubscriberUnsubscribeColumns.test.ts +218 -0
- package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +7 -0
- package/Tests/Server/API/IncidentSubscriberAudienceAPI.test.ts +1408 -0
- package/Tests/Server/API/StatusPageIncidentScope.test.ts +1868 -0
- package/Tests/Server/API/StatusPageIncidentScopePostgres.test.ts +790 -0
- package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +10 -1
- package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +206 -18
- package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +14 -2
- package/Tests/Server/API/StatusPageSubscriberCreateResponse.test.ts +217 -0
- package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +103 -2
- package/Tests/Server/API/StatusPageUnsubscribeAPI.test.ts +396 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentStatusPageScopeMigration.test.ts +395 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentTemplateStatusPageScopeFlagMigration.test.ts +150 -0
- package/Tests/Server/Infrastructure/Postgres/AddSubscriberNotificationClaimedAtMigration.test.ts +156 -0
- package/Tests/Server/Infrastructure/Postgres/SkipHiddenIncidentCreatedNotificationsMigration.test.ts +410 -0
- package/Tests/Server/Middleware/IdentityRateLimit.test.ts +551 -1
- package/Tests/Server/Middleware/SubscriberNotificationPreviewRateLimit.test.ts +238 -0
- package/Tests/Server/Middleware/SubscriberNotificationTestSendRateLimit.test.ts +245 -0
- package/Tests/Server/Services/AddStatusPageSubscriberUnsubscribeTokenMigration.test.ts +152 -0
- package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +221 -36
- package/Tests/Server/Services/DatabaseServiceCompareAndSetColumns.test.ts +191 -0
- package/Tests/Server/Services/IncidentCreatedRenotifyOnPublish.test.ts +681 -0
- package/Tests/Server/Services/IncidentCreatedResend.test.ts +775 -0
- package/Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts +713 -0
- package/Tests/Server/Services/IncidentCustomFieldService.test.ts +751 -0
- package/Tests/Server/Services/IncidentCustomFieldValueValidation.test.ts +556 -0
- package/Tests/Server/Services/IncidentStatusPageScope.test.ts +2971 -0
- package/Tests/Server/Services/IncidentStatusPageScopeFeed.test.ts +131 -0
- package/Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts +625 -0
- package/Tests/Server/Services/IncidentTemplateCustomFieldsCopy.test.ts +311 -0
- package/Tests/Server/Services/IncidentTemplateStatusPageScope.test.ts +363 -0
- package/Tests/Server/Services/PublicNoteEditFeedEventType.test.ts +213 -0
- package/Tests/Server/Services/PublicNoteResendAccess.test.ts +994 -0
- package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +289 -9
- package/Tests/Server/Services/SmsServiceFailIfNotSent.test.ts +67 -0
- package/Tests/Server/Services/StatusPageReportIncidentCounts.test.ts +610 -0
- package/Tests/Server/Services/StatusPageSubscriberAudienceCounts.test.ts +201 -0
- package/Tests/Server/Services/StatusPageSubscriberAudienceCountsPostgres.test.ts +271 -0
- package/Tests/Server/Services/StatusPageSubscriberConfirmationTemplateEscaping.test.ts +200 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationLogRedaction.test.ts +54 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +37 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateIncidentRecordAccess.test.ts +772 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookup.test.ts +506 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookupPostgres.test.ts +261 -0
- package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +21 -5
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribe.test.ts +1618 -0
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribeLinkSenders.test.ts +373 -0
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribePostgres.test.ts +388 -0
- package/Tests/Server/Services/SubscriberNotificationInFlightRequeue.test.ts +500 -0
- package/Tests/Server/Types/MarkdownEmailLinks.test.ts +320 -0
- package/Tests/Server/Types/Workflow/Components/Email.test.ts +491 -1
- package/Tests/Server/Types/Workflow/Components/EmailSmtpPinning.test.ts +398 -0
- package/Tests/Server/Utils/CustomField/CustomFieldRename.test.ts +586 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +246 -10
- package/Tests/Server/Utils/DataSource/EgressGuardDeploymentConfig.test.ts +226 -0
- package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +131 -0
- package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +4 -0
- package/Tests/Server/Utils/EgressPolicyEnvironment.ts +45 -0
- package/Tests/Server/Utils/Mail/PinnedSmtpSocket.test.ts +409 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +23 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionPrivateNetwork.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionResolutionDetail.test.ts +314 -0
- package/Tests/Server/Utils/StatusPage/IncidentStatusPageScope.test.ts +1699 -0
- package/Tests/Server/Utils/StatusPage/IncidentStatusPageScopeQueriesPostgres.test.ts +508 -0
- package/Tests/Server/Utils/StatusPage/IncidentSubscriberAudienceCallerPermission.test.ts +246 -0
- package/Tests/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.test.ts +1348 -0
- package/Tests/Server/Utils/StatusPage/StatusPageReadAccess.test.ts +221 -0
- package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.test.ts +132 -0
- package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.test.ts +155 -0
- package/Tests/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.test.ts +708 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaim.test.ts +255 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaimPostgres.test.ts +528 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.test.ts +1238 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationFanOut.test.ts +472 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.test.ts +1168 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationRunLimit.test.ts +275 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationTiming.test.ts +131 -0
- package/Tests/Server/Utils/StatusPageResource.test.ts +98 -0
- package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +17 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +75 -0
- package/Tests/Types/CustomField/CustomFieldSavedViews.test.ts +247 -0
- package/Tests/Types/CustomField/CustomFieldTemplateValues.test.ts +186 -0
- package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +48 -0
- package/Tests/Types/CustomField/CustomFieldValueFormat.test.ts +215 -0
- package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +343 -0
- package/Tests/Types/CustomField/CustomFieldVariableKey.test.ts +364 -0
- package/Tests/Types/SafeHtml.test.ts +102 -0
- package/Tests/Types/StatusPage/IncidentCreatedRenotify.test.ts +419 -0
- package/Tests/Types/StatusPage/IncidentCreatedResend.test.ts +118 -0
- package/Tests/Types/StatusPage/IncidentScopeAddedPagesNotification.test.ts +558 -0
- package/Tests/Types/StatusPage/IncidentSubscriberAudience.test.ts +284 -0
- package/Tests/Types/StatusPage/StatusPageSubscriberUnsubscribe.test.ts +341 -0
- package/Tests/Types/StatusPage/SubscriberNotificationPreview.test.ts +196 -0
- package/Tests/Types/StatusPage/SubscriberNotificationResend.test.ts +201 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplateCompiler.test.ts +277 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplatePreview.test.ts +179 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +324 -0
- package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +60 -13
- package/Tests/UI/Components/CustomFields/CustomFieldFormFields.test.ts +432 -0
- package/Tests/UI/Components/CustomFields/CustomFieldModelFormFields.test.tsx +685 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetailOrder.test.tsx +469 -0
- package/Tests/UI/Components/Forms/ModelFormCustomFieldInputs.test.tsx +325 -0
- package/Tests/UI/Components/Forms/ModelFormDropdownOptionsRefused.test.tsx +358 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +22 -0
- package/Tests/UI/Monitor/NetworkPathView.test.tsx +289 -0
- package/Tests/Utils/Incident/IncidentNoteTemplateVariables.test.ts +623 -0
- package/Tests/Utils/Markdown/MarkdownEscape.test.ts +89 -0
- package/Tests/Utils/ProbeNetworkFailureUtil.test.ts +992 -0
- package/Tests/Utils/RequestFailedDetails.test.ts +575 -0
- package/Types/CustomField/CustomFieldOrder.ts +55 -0
- package/Types/CustomField/CustomFieldSavedViews.ts +225 -0
- package/Types/CustomField/CustomFieldTemplateMerge.ts +71 -0
- package/Types/CustomField/CustomFieldType.ts +14 -0
- package/Types/CustomField/CustomFieldValueFormat.ts +161 -0
- package/Types/CustomField/CustomFieldValueValidator.ts +488 -0
- package/Types/CustomField/CustomFieldVariableKey.ts +211 -0
- package/Types/SafeHtml.ts +93 -0
- package/Types/StatusPage/IncidentCreatedRenotify.ts +224 -0
- package/Types/StatusPage/IncidentCreatedResend.ts +108 -0
- package/Types/StatusPage/IncidentScopeAddedPagesNotification.ts +343 -0
- package/Types/StatusPage/IncidentSubscriberAudience.ts +332 -0
- package/Types/StatusPage/StatusPageSubscriberUnsubscribe.ts +405 -0
- package/Types/StatusPage/SubscriberNotificationInterruption.ts +32 -0
- package/Types/StatusPage/SubscriberNotificationPreview.ts +322 -0
- package/Types/StatusPage/SubscriberNotificationResend.ts +132 -0
- package/Types/StatusPage/SubscriberNotificationTemplateCompiler.ts +180 -0
- package/Types/StatusPage/SubscriberNotificationTemplatePreview.ts +301 -0
- package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +217 -4
- package/Types/StatusPage/SubscriberUpdateNotification.ts +32 -11
- package/UI/Components/CustomFields/CustomFieldFormFields.ts +317 -0
- package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +395 -0
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +95 -55
- package/UI/Components/Forms/ModelForm.tsx +70 -8
- package/UI/Components/Forms/Validation.ts +1 -1
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +2 -4
- package/UI/Components/ModelTable/AnalyticsModelTable.tsx +2 -6
- package/UI/Components/ModelTable/BaseModelTable.tsx +9 -8
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +14 -1
- package/UI/Components/ModelTable/ModelTable.tsx +6 -7
- package/UI/Utils/SensitiveUrlToken.ts +10 -5
- package/Utils/API.ts +247 -2
- package/Utils/Incident/IncidentNoteTemplateVariables.ts +304 -0
- package/Utils/Markdown/MarkdownEscape.ts +65 -0
- package/Utils/ProbeNetworkFailureUtil.ts +673 -0
- package/build/dist/Models/DatabaseModels/Incident.js +267 -1
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js +207 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js +31 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js +124 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +56 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +131 -0
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +100 -1
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +417 -176
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageSubscriberAPI.js +52 -13
- package/build/dist/Server/API/StatusPageSubscriberAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js +41 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js +57 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js +89 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js +29 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Semaphore.js +3 -0
- package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
- package/build/dist/Server/Middleware/IdentityRateLimit.js +89 -3
- package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
- package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js +149 -0
- package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js.map +1 -0
- package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js +190 -0
- package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js.map +1 -0
- package/build/dist/Server/Services/DatabaseService.js +56 -7
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentCustomFieldService.js +204 -8
- package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +14 -0
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +26 -0
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js +26 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +1052 -0
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +83 -0
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +26 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +47 -17
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/SmsService.js +2 -22
- package/build/dist/Server/Services/SmsService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +47 -9
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +237 -32
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js +109 -0
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +925 -99
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +110 -6
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Email.js +55 -6
- package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
- package/build/dist/Server/Utils/CustomField/CustomFieldRename.js +211 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldRename.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +41 -12
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
- package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js +101 -0
- package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +48 -6
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js +631 -0
- package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js +403 -0
- package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js +451 -0
- package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js +13 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js +91 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js +101 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js +47 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js +273 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js +73 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js +722 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js +102 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js +527 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js +278 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js +137 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js +103 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js +114 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPageResource.js +39 -7
- package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMRunner.js +1 -0
- package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
- package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +3 -0
- package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldOrder.js +36 -0
- package/build/dist/Types/CustomField/CustomFieldOrder.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldSavedViews.js +135 -0
- package/build/dist/Types/CustomField/CustomFieldSavedViews.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js +27 -0
- package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldType.js +12 -0
- package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldValueFormat.js +126 -0
- package/build/dist/Types/CustomField/CustomFieldValueFormat.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js +280 -0
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldVariableKey.js +150 -0
- package/build/dist/Types/CustomField/CustomFieldVariableKey.js.map +1 -0
- package/build/dist/Types/SafeHtml.js +84 -0
- package/build/dist/Types/SafeHtml.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js +117 -0
- package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentCreatedResend.js +86 -0
- package/build/dist/Types/StatusPage/IncidentCreatedResend.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js +246 -0
- package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js +183 -0
- package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js.map +1 -0
- package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js +277 -0
- package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js +27 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js +190 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationResend.js +102 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationResend.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js +97 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js +175 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +144 -4
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -1
- package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +29 -9
- package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js +169 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +212 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +64 -49
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/Forms/ModelForm.js +39 -5
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/Validation.js +1 -1
- package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/AnalyticsModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +2 -2
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +13 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ModelTable.js +1 -1
- package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
- package/build/dist/UI/Utils/SensitiveUrlToken.js +10 -5
- package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -1
- package/build/dist/Utils/API.js +177 -1
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js +155 -0
- package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js.map +1 -0
- package/build/dist/Utils/Markdown/MarkdownEscape.js +48 -0
- package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -1
- package/build/dist/Utils/ProbeNetworkFailureUtil.js +460 -0
- package/build/dist/Utils/ProbeNetworkFailureUtil.js.map +1 -0
- package/package.json +1 -1
|
@@ -15,9 +15,10 @@ import logger from "../Logger";
|
|
|
15
15
|
* It started life guarding external Data Source connections — hence the
|
|
16
16
|
* file's home — but the same policy now covers every sink where a project
|
|
17
17
|
* member picks the host and a self-hosted install may legitimately point at
|
|
18
|
-
* something internal: LLM providers (self-hosted Ollama/vLLM), SMTP
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* something internal: LLM providers (self-hosted Ollama/vLLM), SMTP servers
|
|
19
|
+
* (project SMTP settings and the workflow Send Email step), SMTP OAuth token
|
|
20
|
+
* endpoints, status page / dashboard domain verification, OIDC discovery and
|
|
21
|
+
* Runbook HTTP steps. Sinks that can only ever be third-party
|
|
21
22
|
* SaaS (Slack, Teams, subscriber webhooks) use SSRFProtection instead, which
|
|
22
23
|
* blocks private ranges unconditionally.
|
|
23
24
|
*
|
|
@@ -78,10 +79,21 @@ export interface EgressGuardOptions {
|
|
|
78
79
|
*/
|
|
79
80
|
privateNetworkHint?: string | undefined;
|
|
80
81
|
/*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
82
|
+
* Whether a refused HOSTNAME may say why: which address it resolved to and
|
|
83
|
+
* which policy refused it, or the resolver's own error. That is exactly what
|
|
84
|
+
* an operator needs, and exactly what a tenant must not get — trying names
|
|
85
|
+
* like `redis` or `kubernetes.default.svc.cluster.local` and comparing
|
|
86
|
+
* "resolves to 10.1.2.3" with "could not resolve" maps the internal network
|
|
87
|
+
* without a socket ever being opened. With false, every resolve-path refusal
|
|
88
|
+
* is one sentence ("<Label> host X could not be reached.") and the precise
|
|
89
|
+
* cause goes to the debug log.
|
|
90
|
+
*
|
|
91
|
+
* Undefined ⇒ shouldIncludeResolutionDetail(): detail on a self-hosted
|
|
92
|
+
* install, where whoever configures the target also runs the network; none
|
|
93
|
+
* wherever shouldBlockPrivateAddresses() is true, i.e. multi-tenant SaaS or
|
|
94
|
+
* an operator who asked for SaaS policy. Shared-probe monitor requests pass
|
|
95
|
+
* false outright, whatever the deployment. Literal IPs are unaffected: their
|
|
96
|
+
* refusal echoes only what the caller typed.
|
|
85
97
|
*/
|
|
86
98
|
includeResolvedAddressInError?: boolean | undefined;
|
|
87
99
|
/*
|
|
@@ -196,6 +208,21 @@ export default class DataSourceEgressGuard {
|
|
|
196
208
|
return process.env["BILLING_ENABLED"] === "true";
|
|
197
209
|
}
|
|
198
210
|
|
|
211
|
+
/*
|
|
212
|
+
* Default for EgressGuardOptions.includeResolvedAddressInError, and for the
|
|
213
|
+
* equivalent switch on SSRFProtection. It keys off the private-address
|
|
214
|
+
* POLICY of the deployment, not off any per-call override of it: the oracle
|
|
215
|
+
* exists because the person choosing the target is not trusted with the
|
|
216
|
+
* network's layout, and that is a property of the deployment. So a caller
|
|
217
|
+
* that loosens blockPrivateAddresses on SaaS still gets no detail unless it
|
|
218
|
+
* asks for it explicitly.
|
|
219
|
+
*/
|
|
220
|
+
public static shouldIncludeResolutionDetail(
|
|
221
|
+
includeResolvedAddressInError?: boolean | undefined,
|
|
222
|
+
): boolean {
|
|
223
|
+
return includeResolvedAddressInError ?? !this.shouldBlockPrivateAddresses();
|
|
224
|
+
}
|
|
225
|
+
|
|
199
226
|
private static ipv4ToInt(ip: string): number {
|
|
200
227
|
const parts: Array<string> = ip.split(".");
|
|
201
228
|
let value: number = 0;
|
|
@@ -672,15 +699,19 @@ export default class DataSourceEgressGuard {
|
|
|
672
699
|
return this.defaultResolve(host, options);
|
|
673
700
|
});
|
|
674
701
|
|
|
702
|
+
const includeDetail: boolean = this.shouldIncludeResolutionDetail(
|
|
703
|
+
options?.includeResolvedAddressInError,
|
|
704
|
+
);
|
|
705
|
+
|
|
675
706
|
let addresses: Array<ResolvedAddress> = [];
|
|
676
707
|
try {
|
|
677
708
|
addresses = await resolveFunction(bareHostname);
|
|
678
709
|
} catch (error) {
|
|
679
|
-
if (
|
|
710
|
+
if (!includeDetail) {
|
|
680
711
|
/*
|
|
681
712
|
* The cause is destroyed for the caller by design, so log it here:
|
|
682
|
-
* this is the only place an operator can still learn whether
|
|
683
|
-
*
|
|
713
|
+
* this is the only place an operator can still learn whether the
|
|
714
|
+
* target failed on DNS or on address policy.
|
|
684
715
|
*/
|
|
685
716
|
logger.debug(
|
|
686
717
|
`EgressGuard: could not resolve ${bareHostname} - ${
|
|
@@ -701,7 +732,7 @@ export default class DataSourceEgressGuard {
|
|
|
701
732
|
}
|
|
702
733
|
|
|
703
734
|
if (addresses.length === 0) {
|
|
704
|
-
if (
|
|
735
|
+
if (!includeDetail) {
|
|
705
736
|
logger.debug(`EgressGuard: ${bareHostname} resolved to no addresses.`);
|
|
706
737
|
throw new EgressGuardException(
|
|
707
738
|
`${label} host ${bareHostname} could not be reached.`,
|
|
@@ -720,14 +751,14 @@ export default class DataSourceEgressGuard {
|
|
|
720
751
|
options,
|
|
721
752
|
);
|
|
722
753
|
if (verdict.blocked) {
|
|
723
|
-
if (
|
|
754
|
+
if (!includeDetail) {
|
|
724
755
|
logger.debug(
|
|
725
|
-
`EgressGuard: ${bareHostname} resolved to a blocked address - ${verdict.reason}.`,
|
|
756
|
+
`EgressGuard: ${bareHostname} resolved to a blocked address ${resolved.address} - ${verdict.reason}.`,
|
|
726
757
|
);
|
|
727
758
|
/*
|
|
728
759
|
* Reported as Unreachable, NOT AddressBlocked. Sharing one reason
|
|
729
|
-
* with the DNS branches above is what stops a tenant
|
|
730
|
-
*
|
|
760
|
+
* with the DNS branches above is what stops a tenant from using the
|
|
761
|
+
* difference to enumerate internal names.
|
|
731
762
|
*/
|
|
732
763
|
throw new EgressGuardException(
|
|
733
764
|
`${label} host ${bareHostname} could not be reached.`,
|
|
@@ -798,6 +829,15 @@ export default class DataSourceEgressGuard {
|
|
|
798
829
|
* that was checked the address that gets dialed, closing the DNS-rebind
|
|
799
830
|
* window between validation and connect. TLS still verifies against the
|
|
800
831
|
* original hostname because SNI is taken from the URL, not from here.
|
|
832
|
+
*
|
|
833
|
+
* It always answers asynchronously, the way dns.lookup does. Node's
|
|
834
|
+
* net/tls connect can fail every pinned address synchronously (a probe
|
|
835
|
+
* with no IPv6 gets EADDRNOTAVAIL or ENETUNREACH from connect() itself),
|
|
836
|
+
* and when the lookup has answered synchronously that destroys the
|
|
837
|
+
* TLSSocket before tls.connect calls setServername on it. The request then
|
|
838
|
+
* throws "Cannot read properties of null (reading 'setServername')" in
|
|
839
|
+
* place of the real connect error, and that error escapes as an unhandled
|
|
840
|
+
* 'error' event on the socket.
|
|
801
841
|
*/
|
|
802
842
|
public static createPinnedLookup(
|
|
803
843
|
addresses: Array<ResolvedAddress>,
|
|
@@ -823,22 +863,27 @@ export default class DataSourceEgressGuard {
|
|
|
823
863
|
`No IPv${wantedFamily} address is available for the validated host.`,
|
|
824
864
|
);
|
|
825
865
|
error.code = "ENOTFOUND";
|
|
826
|
-
|
|
866
|
+
process.nextTick(() => {
|
|
867
|
+
callback(error, "");
|
|
868
|
+
});
|
|
827
869
|
return;
|
|
828
870
|
}
|
|
829
871
|
|
|
830
872
|
if (lookupOptions && lookupOptions.all) {
|
|
831
|
-
|
|
832
|
-
null,
|
|
873
|
+
const allAddresses: Array<{ address: string; family: number }> =
|
|
833
874
|
usableAddresses.map((resolved: ResolvedAddress) => {
|
|
834
875
|
return { address: resolved.address, family: resolved.family };
|
|
835
|
-
})
|
|
836
|
-
)
|
|
876
|
+
});
|
|
877
|
+
process.nextTick(() => {
|
|
878
|
+
callback(null, allAddresses);
|
|
879
|
+
});
|
|
837
880
|
return;
|
|
838
881
|
}
|
|
839
882
|
|
|
840
883
|
const first: ResolvedAddress = usableAddresses[0]!;
|
|
841
|
-
|
|
884
|
+
process.nextTick(() => {
|
|
885
|
+
callback(null, first.address, first.family);
|
|
886
|
+
});
|
|
842
887
|
};
|
|
843
888
|
}
|
|
844
889
|
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import net from "net";
|
|
2
|
+
import DataSourceEgressGuard, {
|
|
3
|
+
ResolvedAddress,
|
|
4
|
+
} from "../DataSource/EgressGuard";
|
|
5
|
+
|
|
6
|
+
// What nodemailer's getSocket hook hands back: an already connected socket.
|
|
7
|
+
export type SmtpSocketCallback = (
|
|
8
|
+
error: Error | null,
|
|
9
|
+
socketOptions?: { connection: net.Socket },
|
|
10
|
+
) => void;
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* The socket half of pinning a tenant-chosen SMTP server to the addresses
|
|
14
|
+
* the egress guard validated.
|
|
15
|
+
*
|
|
16
|
+
* Given a host name, nodemailer resolves it again on its own (dns.resolve4/6,
|
|
17
|
+
* falling back to dns.lookup, behind a process-wide cache kept for five
|
|
18
|
+
* minutes whatever the record's TTL), so a DNS answer that changed after the
|
|
19
|
+
* check would choose the address actually connected to. Callers validate the
|
|
20
|
+
* host, open the socket here, and hand it to nodemailer through its getSocket
|
|
21
|
+
* hook as `{ connection: socket }`; nodemailer then resolves and dials
|
|
22
|
+
* nothing itself.
|
|
23
|
+
*
|
|
24
|
+
* nodemailer still gets the name the user typed as `host`: it is what TLS
|
|
25
|
+
* sends as SNI and checks the certificate against, on implicit TLS and on the
|
|
26
|
+
* STARTTLS upgrade alike.
|
|
27
|
+
*
|
|
28
|
+
* Used by the workflow Send Email component and by MailService for project
|
|
29
|
+
* SMTP configs.
|
|
30
|
+
*/
|
|
31
|
+
export default class PinnedSmtpSocket {
|
|
32
|
+
/*
|
|
33
|
+
* Open a TCP connection that can only reach the given, already validated
|
|
34
|
+
* addresses.
|
|
35
|
+
*
|
|
36
|
+
* The pinned lookup answers with every validated address, and
|
|
37
|
+
* autoSelectFamily tries them in turn, alternating families. That keeps
|
|
38
|
+
* what nodemailer did when it resolved the name itself: a host whose
|
|
39
|
+
* address family this worker cannot route (IPv4 on an IPv6-only cluster),
|
|
40
|
+
* or one record that is down, falls through to the next address instead
|
|
41
|
+
* of failing the send.
|
|
42
|
+
*
|
|
43
|
+
* timeoutInMs bounds the TCP connect. nodemailer's own connectionTimeout
|
|
44
|
+
* only starts once it is handed the connected socket, so without this a
|
|
45
|
+
* blackholed address would hang the send.
|
|
46
|
+
*/
|
|
47
|
+
public static connect(data: {
|
|
48
|
+
host: string;
|
|
49
|
+
port: number;
|
|
50
|
+
addresses: Array<ResolvedAddress>;
|
|
51
|
+
timeoutInMs: number;
|
|
52
|
+
onDone: SmtpSocketCallback;
|
|
53
|
+
}): void {
|
|
54
|
+
const socket: net.Socket = net.connect({
|
|
55
|
+
host: data.host,
|
|
56
|
+
port: data.port,
|
|
57
|
+
lookup: DataSourceEgressGuard.createPinnedLookup(data.addresses) as never,
|
|
58
|
+
autoSelectFamily: true,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
let settled: boolean = false;
|
|
62
|
+
|
|
63
|
+
const settle: (error: Error | null) => void = (
|
|
64
|
+
error: Error | null,
|
|
65
|
+
): void => {
|
|
66
|
+
if (settled) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
settled = true;
|
|
71
|
+
socket.setTimeout(0);
|
|
72
|
+
|
|
73
|
+
if (error) {
|
|
74
|
+
// A late error from a socket nobody owns would crash the process.
|
|
75
|
+
socket.on("error", () => {});
|
|
76
|
+
socket.destroy();
|
|
77
|
+
data.onDone(error);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/*
|
|
82
|
+
* nodemailer attaches its own error and timeout handlers synchronously
|
|
83
|
+
* inside this callback, so the socket is never left unwatched. The
|
|
84
|
+
* listeners below stay behind as no-ops.
|
|
85
|
+
*/
|
|
86
|
+
data.onDone(null, { connection: socket });
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
socket.once("connect", () => {
|
|
90
|
+
settle(null);
|
|
91
|
+
});
|
|
92
|
+
socket.once("error", (error: Error) => {
|
|
93
|
+
settle(PinnedSmtpSocket.describeConnectionError(error));
|
|
94
|
+
});
|
|
95
|
+
socket.once("timeout", () => {
|
|
96
|
+
settle(new Error("Connection timeout"));
|
|
97
|
+
});
|
|
98
|
+
socket.setTimeout(data.timeoutInMs);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/*
|
|
102
|
+
* When every address fails, autoSelectFamily reports an AggregateError
|
|
103
|
+
* whose own message is empty, which would reach the user as a generic
|
|
104
|
+
* "could not be sent". Name each attempt instead, the way nodemailer's
|
|
105
|
+
* "connect ECONNREFUSED <ip>:<port>" did.
|
|
106
|
+
*/
|
|
107
|
+
public static describeConnectionError(error: Error): Error {
|
|
108
|
+
const attempts: unknown = (error as { errors?: unknown }).errors;
|
|
109
|
+
|
|
110
|
+
if (error.message || !Array.isArray(attempts) || attempts.length === 0) {
|
|
111
|
+
return error;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const described: NodeJS.ErrnoException = new Error(
|
|
115
|
+
attempts
|
|
116
|
+
.map((attempt: unknown) => {
|
|
117
|
+
const message: unknown = (attempt as { message?: unknown } | null)
|
|
118
|
+
?.message;
|
|
119
|
+
return typeof message === "string" ? message : String(attempt);
|
|
120
|
+
})
|
|
121
|
+
.join("; "),
|
|
122
|
+
);
|
|
123
|
+
const code: string | undefined = (error as NodeJS.ErrnoException).code;
|
|
124
|
+
if (code) {
|
|
125
|
+
described.code = code;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return described;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -36,6 +36,7 @@ import MonitorMetricType from "../../../Types/Monitor/MonitorMetricType";
|
|
|
36
36
|
import MonitorCriteriaMessageFormatter from "./MonitorCriteriaMessageFormatter";
|
|
37
37
|
import MonitorCriteriaDataExtractor from "./MonitorCriteriaDataExtractor";
|
|
38
38
|
import MonitorCriteriaExpectationBuilder from "./MonitorCriteriaExpectationBuilder";
|
|
39
|
+
import ProbeNetworkFailureUtil from "../../../Utils/ProbeNetworkFailureUtil";
|
|
39
40
|
import MetricMonitorResponse from "../../../Types/Monitor/MetricMonitor/MetricMonitorResponse";
|
|
40
41
|
import MetricQueryConfigData from "../../../Types/Metrics/MetricQueryConfigData";
|
|
41
42
|
import MetricFormulaConfigData from "../../../Types/Metrics/MetricFormulaConfigData";
|
|
@@ -1556,6 +1557,15 @@ export default class MonitorCriteriaObservationBuilder {
|
|
|
1556
1557
|
return "Device is reachable (answered ping or SNMP).";
|
|
1557
1558
|
}
|
|
1558
1559
|
|
|
1560
|
+
/*
|
|
1561
|
+
* A probe that could not send at all (no IPv6 on the probe, say) never
|
|
1562
|
+
* contacted the device, so "unreachable" would be a verdict on a device
|
|
1563
|
+
* nobody checked, and would contradict the cause that follows it.
|
|
1564
|
+
*/
|
|
1565
|
+
if (ProbeNetworkFailureUtil.isProbeSideCause(probeResponse.failureCause)) {
|
|
1566
|
+
return `Device could not be checked from this probe: ${probeResponse.failureCause}`;
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1559
1569
|
if (probeResponse.failureCause) {
|
|
1560
1570
|
return `Device is unreachable by ping and SNMP: ${probeResponse.failureCause}`;
|
|
1561
1571
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import URL from "../../Types/API/URL";
|
|
2
2
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
3
|
+
import DataSourceEgressGuard from "./DataSource/EgressGuard";
|
|
4
|
+
import logger from "./Logger";
|
|
3
5
|
import PrivateNetworkWebhookConfig from "./PrivateNetworkWebhookConfig";
|
|
4
6
|
import dns from "dns";
|
|
5
7
|
import net from "net";
|
|
@@ -101,6 +103,21 @@ export interface WebhookTargetValidationOptions {
|
|
|
101
103
|
* filing the bug this feature came from.
|
|
102
104
|
*/
|
|
103
105
|
privateNetworkHint?: string | undefined;
|
|
106
|
+
|
|
107
|
+
/*
|
|
108
|
+
* Whether a refusal decided by DNS may say what DNS answered. "could not be
|
|
109
|
+
* resolved via DNS" next to "resolves to a private network address" tells
|
|
110
|
+
* whoever typed the URL which internal names exist, so without detail every
|
|
111
|
+
* such refusal is the one sentence "<label> could not be reached." and the
|
|
112
|
+
* precise cause goes to the debug log. Refusals of an IP literal or a
|
|
113
|
+
* well-known local name keep their detail: they only restate the URL.
|
|
114
|
+
*
|
|
115
|
+
* Undefined ⇒ DataSourceEgressGuard.shouldIncludeResolutionDetail(), the
|
|
116
|
+
* same default the egress guard uses: detail on a self-hosted install, none
|
|
117
|
+
* on SaaS or wherever the operator forced SaaS policy. A shared probe passes
|
|
118
|
+
* false whatever its deployment.
|
|
119
|
+
*/
|
|
120
|
+
includeResolutionDetailInError?: boolean | undefined;
|
|
104
121
|
}
|
|
105
122
|
|
|
106
123
|
export interface ValidatedWebhookTargetAddress {
|
|
@@ -215,6 +232,10 @@ export default class SSRFProtection {
|
|
|
215
232
|
const label: string = options?.targetLabel || DEFAULT_TARGET_LABEL;
|
|
216
233
|
const privateNetworkHint: string =
|
|
217
234
|
options?.privateNetworkHint ?? DEFAULT_PRIVATE_NETWORK_HINT;
|
|
235
|
+
const includeResolutionDetail: boolean =
|
|
236
|
+
DataSourceEgressGuard.shouldIncludeResolutionDetail(
|
|
237
|
+
options?.includeResolutionDetailInError,
|
|
238
|
+
);
|
|
218
239
|
|
|
219
240
|
/*
|
|
220
241
|
* URL.fromString only knows http/https/ws/wss/mongodb/mailto/tel/sms and
|
|
@@ -373,16 +394,24 @@ export default class SSRFProtection {
|
|
|
373
394
|
let resolved: Array<{ address: string; family: number }> = [];
|
|
374
395
|
try {
|
|
375
396
|
resolved = await dns.promises.lookup(host, { all: true });
|
|
376
|
-
} catch {
|
|
377
|
-
throw
|
|
378
|
-
|
|
379
|
-
|
|
397
|
+
} catch (error) {
|
|
398
|
+
throw SSRFProtection.refuseResolvedHost({
|
|
399
|
+
label: label,
|
|
400
|
+
includeDetail: includeResolutionDetail,
|
|
401
|
+
detailedMessage: `${label} hostname could not be resolved via DNS.`,
|
|
402
|
+
cause: `${host} could not be resolved - ${
|
|
403
|
+
error instanceof Error ? error.message : String(error)
|
|
404
|
+
}`,
|
|
405
|
+
});
|
|
380
406
|
}
|
|
381
407
|
|
|
382
408
|
if (resolved.length === 0 && isConnectionHostname) {
|
|
383
|
-
throw
|
|
384
|
-
|
|
385
|
-
|
|
409
|
+
throw SSRFProtection.refuseResolvedHost({
|
|
410
|
+
label: label,
|
|
411
|
+
includeDetail: includeResolutionDetail,
|
|
412
|
+
detailedMessage: `${label} hostname could not be resolved via DNS.`,
|
|
413
|
+
cause: `${host} resolved to no addresses`,
|
|
414
|
+
});
|
|
386
415
|
}
|
|
387
416
|
|
|
388
417
|
const normalizedAddresses: Array<ValidatedWebhookTargetAddress> =
|
|
@@ -420,15 +449,21 @@ export default class SSRFProtection {
|
|
|
420
449
|
SSRFProtection.classifyHostnameLiteral(address);
|
|
421
450
|
|
|
422
451
|
if (tier === WebhookAddressTier.Forbidden) {
|
|
423
|
-
throw
|
|
424
|
-
|
|
425
|
-
|
|
452
|
+
throw SSRFProtection.refuseResolvedHost({
|
|
453
|
+
label: label,
|
|
454
|
+
includeDetail: includeResolutionDetail,
|
|
455
|
+
detailedMessage: `${label} resolves to a private, loopback, or link-local address and is not allowed.`,
|
|
456
|
+
cause: `${host} resolved to ${address}, which is forbidden`,
|
|
457
|
+
});
|
|
426
458
|
}
|
|
427
459
|
|
|
428
460
|
if (tier === WebhookAddressTier.Private && !isPrivateTierAllowed) {
|
|
429
|
-
throw
|
|
430
|
-
|
|
431
|
-
|
|
461
|
+
throw SSRFProtection.refuseResolvedHost({
|
|
462
|
+
label: label,
|
|
463
|
+
includeDetail: includeResolutionDetail,
|
|
464
|
+
detailedMessage: `${label} resolves to a private network address and is not allowed.${privateNetworkHint}`,
|
|
465
|
+
cause: `${host} resolved to ${address}, a private network address`,
|
|
466
|
+
});
|
|
432
467
|
}
|
|
433
468
|
}
|
|
434
469
|
}
|
|
@@ -453,14 +488,39 @@ export default class SSRFProtection {
|
|
|
453
488
|
resolvedAddressesByHostname.get(whatwgHostname);
|
|
454
489
|
|
|
455
490
|
if (!addresses || addresses.length === 0) {
|
|
456
|
-
throw
|
|
457
|
-
|
|
458
|
-
|
|
491
|
+
throw SSRFProtection.refuseResolvedHost({
|
|
492
|
+
label: label,
|
|
493
|
+
includeDetail: includeResolutionDetail,
|
|
494
|
+
detailedMessage: `${label} hostname could not be resolved via DNS.`,
|
|
495
|
+
cause: `${whatwgHostname} resolved to no addresses`,
|
|
496
|
+
});
|
|
459
497
|
}
|
|
460
498
|
|
|
461
499
|
return { url: canonicalUrl, addresses: addresses };
|
|
462
500
|
}
|
|
463
501
|
|
|
502
|
+
/*
|
|
503
|
+
* The refusal for a hostname whose DNS answer decided the outcome. Without
|
|
504
|
+
* detail, a name that does not exist and a name that resolves somewhere
|
|
505
|
+
* internal produce the same sentence — that sameness is the whole point, so
|
|
506
|
+
* nothing about the cause may reach the message — and the operator learns
|
|
507
|
+
* the difference from the debug log instead.
|
|
508
|
+
*/
|
|
509
|
+
private static refuseResolvedHost(data: {
|
|
510
|
+
label: string;
|
|
511
|
+
includeDetail: boolean;
|
|
512
|
+
detailedMessage: string;
|
|
513
|
+
cause: string;
|
|
514
|
+
}): BadDataException {
|
|
515
|
+
if (data.includeDetail) {
|
|
516
|
+
return new BadDataException(data.detailedMessage);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
logger.debug(`SSRFProtection: ${data.cause}.`);
|
|
520
|
+
|
|
521
|
+
return new BadDataException(`${data.label} could not be reached.`);
|
|
522
|
+
}
|
|
523
|
+
|
|
464
524
|
/*
|
|
465
525
|
* Everything up to and including the LAST "@" is userinfo, never the host.
|
|
466
526
|
*
|