@oneuptime/common 13.0.8 → 14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/AnalyticsModels/AuditLog.ts +23 -15
- package/Models/DatabaseModels/GlobalConfig.ts +24 -0
- package/Models/DatabaseModels/Monitor.ts +3 -2
- package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
- package/Scripts/generate-service-worker.js +65 -4
- package/Server/API/BaseAPI.ts +26 -5
- package/Server/API/GlobalConfigAPI.ts +228 -462
- package/Server/API/ProjectOIDC.ts +25 -16
- package/Server/API/ProjectSSO.ts +24 -16
- package/Server/API/StatusPageAPI.ts +100 -42
- package/Server/API/TeamMemberAPI.ts +10 -1
- package/Server/Enterprise/EnterpriseEdition.ts +649 -0
- package/Server/Enterprise/EnterpriseFeature.ts +48 -0
- package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
- package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
- package/Server/EnvironmentConfig.ts +147 -2
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Middleware/UserAuthorization.ts +38 -16
- package/Server/Services/AuditLogService.ts +84 -1079
- package/Server/Services/EnterpriseLicenseService.ts +38 -0
- package/Server/Services/GlobalConfigService.ts +80 -1
- package/Server/Services/MonitorProbeService.ts +116 -20
- package/Server/Services/MonitorService.ts +56 -4
- package/Server/Services/MonitorStatusTimelineService.ts +284 -0
- package/Server/Services/MonitorTemplateService.ts +26 -0
- package/Server/Services/ProjectService.ts +284 -0
- package/Server/Services/RumSessionPinService.ts +25 -6
- package/Server/Services/StatusPagePrivateUserService.ts +7 -3
- package/Server/Services/StatusPageService.ts +78 -1
- package/Server/Services/TeamMemberService.ts +11 -0
- package/Server/Services/TeamService.ts +10 -0
- package/Server/Services/UserService.ts +10 -17
- package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
- package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
- package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
- package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
- package/Server/Types/Markdown.ts +41 -0
- package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
- package/Server/Utils/EditionEnforcement.ts +233 -0
- package/Server/Utils/FrontendEnvironment.ts +41 -2
- package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
- package/Server/Utils/Monitor/AffectedResourceList.ts +190 -0
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +543 -333
- package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
- package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
- package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
- package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
- package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
- package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
- package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
- package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
- package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
- package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
- package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
- package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
- package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
- package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
- package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
- package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
- package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
- package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
- package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
- package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
- package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
- package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
- package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
- package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
- package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
- package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
- package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
- package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
- package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
- package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
- package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
- package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
- package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
- package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
- package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
- package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
- package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
- package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
- package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
- package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
- package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
- package/Tests/Server/Services/AuditLogService.test.ts +460 -990
- package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
- package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
- package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
- package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
- package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
- package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
- package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
- package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
- package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
- package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
- package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
- package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
- package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
- package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
- package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
- package/Tests/Server/Types/Markdown.test.ts +181 -0
- package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
- package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
- package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
- package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
- package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
- package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +934 -96
- package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
- package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
- package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
- package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
- package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
- package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
- package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
- package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
- package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
- package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
- package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
- package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
- package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
- package/Tests/Utils/HostAddressUtil.test.ts +138 -0
- package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
- package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
- package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
- package/Types/API/Hostname.ts +63 -16
- package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
- package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
- package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
- package/Types/Database/CanonicalModelInstance.ts +102 -0
- package/Types/Database/TableColumn.ts +20 -6
- package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
- package/Types/IP/IPv6.ts +6 -1
- package/Types/Monitor/MonitorStep.ts +6 -1
- package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
- package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
- package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
- package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
- package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/ModelList/ModelList.tsx +11 -1
- package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
- package/UI/esbuild-enterprise.js +263 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
- package/Utils/HostAddressUtil.ts +94 -0
- package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
- package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
- package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
- package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
- package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +26 -5
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectOIDC.js +24 -16
- package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
- package/build/dist/Server/API/ProjectSSO.js +24 -16
- package/build/dist/Server/API/ProjectSSO.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +93 -43
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TeamMemberAPI.js +8 -1
- package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
- package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
- package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
- package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
- package/build/dist/Server/EnvironmentConfig.js +84 -2
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/AuditLogService.js +71 -740
- package/build/dist/Server/Services/AuditLogService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
- package/build/dist/Server/Services/GlobalConfigService.js +63 -0
- package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
- package/build/dist/Server/Services/MonitorProbeService.js +90 -17
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +45 -4
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +214 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionPinService.js +24 -6
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +71 -0
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +10 -0
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamService.js +9 -0
- package/build/dist/Server/Services/TeamService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +10 -16
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +31 -0
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
- package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
- package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
- package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
- package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +96 -0
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +449 -261
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
- package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Types/API/Hostname.js +59 -11
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
- package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
- package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
- package/build/dist/Types/Database/TableColumn.js +19 -6
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
- package/build/dist/Types/IP/IPv6.js +6 -1
- package/build/dist/Types/IP/IPv6.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +5 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
- package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
- package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
- package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
- package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
- package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
- package/build/dist/Utils/HostAddressUtil.js +80 -0
- package/build/dist/Utils/HostAddressUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
- package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
- package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
- package/jest.config.json +3 -1
- package/package.json +1 -1
- package/test-setup.sh +103 -34
- package/tsconfig.json +13 -0
- package/Server/API/EnterpriseLicenseAPI.ts +0 -925
- package/Server/API/TeamComplianceAPI.ts +0 -158
- package/Server/Middleware/SCIMAuthorization.ts +0 -141
- package/Server/Services/TeamComplianceService.ts +0 -733
- package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
- package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
- package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
- package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
- package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
- package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
- package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
- package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
- package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
- package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
- package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
- package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
- package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
- package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
- package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
- package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
- package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
- package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
- package/build/dist/Server/Services/TeamComplianceService.js +0 -537
- package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
2
|
-
import "@testing-library/jest-dom";
|
|
3
|
-
import { cleanup } from "@testing-library/react";
|
|
4
|
-
import * as React from "react";
|
|
5
|
-
import SecurityEventsSideMenu from "../../../../App/FeatureSet/Dashboard/src/Pages/SecurityEvents/SideMenu";
|
|
6
|
-
import { getSecurityEventsBreadcrumbs } from "../../../../App/FeatureSet/Dashboard/src/Utils/Breadcrumbs/SecurityEventsBreadcrumbs";
|
|
7
|
-
import PageMap from "../../../../App/FeatureSet/Dashboard/src/Utils/PageMap";
|
|
8
|
-
import { RouteUtil } from "../../../../App/FeatureSet/Dashboard/src/Utils/RouteMap";
|
|
9
|
-
import Link from "../../../Types/Link";
|
|
10
|
-
import {
|
|
11
|
-
allLinks,
|
|
12
|
-
DESKTOP_WIDTH,
|
|
13
|
-
hrefsInMenu,
|
|
14
|
-
iconCountIn,
|
|
15
|
-
isExpanded,
|
|
16
|
-
linksIn,
|
|
17
|
-
MenuLink,
|
|
18
|
-
MOBILE_WIDTH,
|
|
19
|
-
mobileSummaryText,
|
|
20
|
-
PROJECT_ID,
|
|
21
|
-
goTo,
|
|
22
|
-
renderMenu,
|
|
23
|
-
routeFor,
|
|
24
|
-
sectionTitlesInOrder,
|
|
25
|
-
setViewportWidth,
|
|
26
|
-
titlesInMenu,
|
|
27
|
-
} from "./SideMenuHarness";
|
|
28
|
-
|
|
29
|
-
interface ExpectedMenuEntry {
|
|
30
|
-
title: string;
|
|
31
|
-
pageMapKey: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface ExpectedMenuSection {
|
|
35
|
-
title: string;
|
|
36
|
-
entries: Array<ExpectedMenuEntry>;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface MobileMenuCase extends ExpectedMenuEntry {
|
|
40
|
-
expectedSummary: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const EXPECTED_SECTIONS: Array<ExpectedMenuSection> = [
|
|
44
|
-
{
|
|
45
|
-
title: "Security Events",
|
|
46
|
-
entries: [
|
|
47
|
-
{ title: "Events", pageMapKey: PageMap.SECURITY_EVENTS },
|
|
48
|
-
{
|
|
49
|
-
title: "Correlate",
|
|
50
|
-
pageMapKey: PageMap.SECURITY_EVENTS_CORRELATE,
|
|
51
|
-
},
|
|
52
|
-
],
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
title: "Detection & Alerting",
|
|
56
|
-
entries: [
|
|
57
|
-
{
|
|
58
|
-
title: "Detection Rules",
|
|
59
|
-
pageMapKey: PageMap.SECURITY_EVENTS_DETECTION_RULES,
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
title: "Threat Intel",
|
|
63
|
-
pageMapKey: PageMap.SECURITY_EVENTS_THREAT_INTEL,
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
title: "Monitors",
|
|
67
|
-
pageMapKey: PageMap.SECURITY_EVENTS_MONITORS,
|
|
68
|
-
},
|
|
69
|
-
],
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
title: "Integrations",
|
|
73
|
-
entries: [
|
|
74
|
-
{
|
|
75
|
-
title: "Connections",
|
|
76
|
-
pageMapKey: PageMap.SECURITY_EVENTS_CONNECTIONS,
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
title: "Help",
|
|
82
|
-
entries: [
|
|
83
|
-
{
|
|
84
|
-
title: "Setup Guide",
|
|
85
|
-
pageMapKey: PageMap.SECURITY_EVENTS_DOCUMENTATION,
|
|
86
|
-
},
|
|
87
|
-
],
|
|
88
|
-
},
|
|
89
|
-
];
|
|
90
|
-
|
|
91
|
-
const EXPECTED_ENTRIES: Array<ExpectedMenuEntry> = EXPECTED_SECTIONS.flatMap(
|
|
92
|
-
(section: ExpectedMenuSection): Array<ExpectedMenuEntry> => {
|
|
93
|
-
return section.entries;
|
|
94
|
-
},
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
const MOBILE_MENU_CASES: Array<MobileMenuCase> = EXPECTED_SECTIONS.flatMap(
|
|
98
|
-
(section: ExpectedMenuSection): Array<MobileMenuCase> => {
|
|
99
|
-
return section.entries.map((entry: ExpectedMenuEntry): MobileMenuCase => {
|
|
100
|
-
return {
|
|
101
|
-
...entry,
|
|
102
|
-
expectedSummary: `${section.title} / ${entry.title}`,
|
|
103
|
-
};
|
|
104
|
-
});
|
|
105
|
-
},
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
function expectedLinks(section: ExpectedMenuSection): Array<MenuLink> {
|
|
109
|
-
return section.entries.map((entry: ExpectedMenuEntry): MenuLink => {
|
|
110
|
-
return {
|
|
111
|
-
title: entry.title,
|
|
112
|
-
href: routeFor(entry.pageMapKey),
|
|
113
|
-
};
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function findAnchor(title: string): HTMLAnchorElement {
|
|
118
|
-
const anchor: HTMLAnchorElement | undefined = Array.from(
|
|
119
|
-
document.querySelectorAll("a"),
|
|
120
|
-
).find((candidate: Element): boolean => {
|
|
121
|
-
return candidate.querySelector("span.truncate")?.textContent === title;
|
|
122
|
-
}) as HTMLAnchorElement | undefined;
|
|
123
|
-
|
|
124
|
-
if (!anchor) {
|
|
125
|
-
throw new Error(`No side-menu link titled "${title}" was rendered.`);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return anchor;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function expectActiveLink(title: string): void {
|
|
132
|
-
const anchor: HTMLAnchorElement = findAnchor(title);
|
|
133
|
-
|
|
134
|
-
expect(anchor).toHaveClass("text-indigo-700");
|
|
135
|
-
expect(anchor).not.toHaveClass("text-gray-600");
|
|
136
|
-
expect(anchor.querySelector(".bg-indigo-600")).not.toBeNull();
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
describe("Security Events side menu", () => {
|
|
140
|
-
beforeEach(() => {
|
|
141
|
-
setViewportWidth(DESKTOP_WIDTH);
|
|
142
|
-
goTo(`/dashboard/${PROJECT_ID}/security-events`);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
afterEach(() => {
|
|
146
|
-
cleanup();
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
test("groups every destination into the intended section and order", async () => {
|
|
150
|
-
await renderMenu(<SecurityEventsSideMenu />);
|
|
151
|
-
|
|
152
|
-
expect(sectionTitlesInOrder()).toEqual(
|
|
153
|
-
EXPECTED_SECTIONS.map((section: ExpectedMenuSection): string => {
|
|
154
|
-
return section.title;
|
|
155
|
-
}),
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
for (const section of EXPECTED_SECTIONS) {
|
|
159
|
-
expect(linksIn(section.title)).toEqual(expectedLinks(section));
|
|
160
|
-
expect(isExpanded(section.title)).toBe(true);
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
test("keeps all seven concrete routes reachable exactly once with icons", async () => {
|
|
165
|
-
await renderMenu(<SecurityEventsSideMenu />);
|
|
166
|
-
|
|
167
|
-
const expectedHrefs: Array<string> = EXPECTED_ENTRIES.map(
|
|
168
|
-
(entry: ExpectedMenuEntry): string => {
|
|
169
|
-
return routeFor(entry.pageMapKey);
|
|
170
|
-
},
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
expect(allLinks()).toHaveLength(7);
|
|
174
|
-
expect(hrefsInMenu().sort()).toEqual(expectedHrefs.sort());
|
|
175
|
-
expect(hrefsInMenu()).toEqual(Array.from(new Set(hrefsInMenu())));
|
|
176
|
-
expect(titlesInMenu()).toEqual(Array.from(new Set(titlesInMenu())));
|
|
177
|
-
|
|
178
|
-
for (const section of EXPECTED_SECTIONS) {
|
|
179
|
-
expect(iconCountIn(section.title)).toBe(section.entries.length);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
for (const href of hrefsInMenu()) {
|
|
183
|
-
expect(href.startsWith(`/dashboard/${PROJECT_ID}/`)).toBe(true);
|
|
184
|
-
expect(href).not.toContain(":projectId");
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
test.each(EXPECTED_ENTRIES)(
|
|
189
|
-
"$title is highlighted on its route",
|
|
190
|
-
async (entry: ExpectedMenuEntry): Promise<void> => {
|
|
191
|
-
goTo(routeFor(entry.pageMapKey));
|
|
192
|
-
|
|
193
|
-
await renderMenu(<SecurityEventsSideMenu />);
|
|
194
|
-
|
|
195
|
-
expectActiveLink(entry.title);
|
|
196
|
-
expect(
|
|
197
|
-
Array.from(document.querySelectorAll("a.text-indigo-700")),
|
|
198
|
-
).toHaveLength(1);
|
|
199
|
-
},
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
test("keeps Events selected when the product route has a trailing slash", async () => {
|
|
203
|
-
goTo(`${routeFor(PageMap.SECURITY_EVENTS)}/`);
|
|
204
|
-
|
|
205
|
-
await renderMenu(<SecurityEventsSideMenu />);
|
|
206
|
-
|
|
207
|
-
expectActiveLink("Events");
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
test.each(MOBILE_MENU_CASES)(
|
|
211
|
-
"$title is named with its section in the mobile menu",
|
|
212
|
-
async (entry: MobileMenuCase): Promise<void> => {
|
|
213
|
-
setViewportWidth(MOBILE_WIDTH);
|
|
214
|
-
goTo(routeFor(entry.pageMapKey));
|
|
215
|
-
|
|
216
|
-
await renderMenu(<SecurityEventsSideMenu />);
|
|
217
|
-
|
|
218
|
-
expect(mobileSummaryText()).toContain(entry.expectedSummary);
|
|
219
|
-
},
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
test("keeps the Events mobile label when the product route has a trailing slash", async () => {
|
|
223
|
-
setViewportWidth(MOBILE_WIDTH);
|
|
224
|
-
goTo(`${routeFor(PageMap.SECURITY_EVENTS)}/`);
|
|
225
|
-
|
|
226
|
-
await renderMenu(<SecurityEventsSideMenu />);
|
|
227
|
-
|
|
228
|
-
expect(mobileSummaryText()).toContain("Security Events / Events");
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
test("keeps every menu label aligned with its breadcrumb leaf", async () => {
|
|
232
|
-
await renderMenu(<SecurityEventsSideMenu />);
|
|
233
|
-
|
|
234
|
-
for (const entry of EXPECTED_ENTRIES) {
|
|
235
|
-
const trail: Array<Link> | undefined = getSecurityEventsBreadcrumbs(
|
|
236
|
-
RouteUtil.getRouteString(entry.pageMapKey),
|
|
237
|
-
);
|
|
238
|
-
|
|
239
|
-
expect(trail).toBeDefined();
|
|
240
|
-
expect(trail?.[trail.length - 1]?.title).toBe(
|
|
241
|
-
entry.pageMapKey === PageMap.SECURITY_EVENTS
|
|
242
|
-
? "Security Events"
|
|
243
|
-
: entry.title,
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
});
|
|
@@ -1,382 +0,0 @@
|
|
|
1
|
-
import "@testing-library/jest-dom";
|
|
2
|
-
import { cleanup, render } from "@testing-library/react";
|
|
3
|
-
import { afterEach, describe, expect, test } from "@jest/globals";
|
|
4
|
-
|
|
5
|
-
import securityEventColumns from "../../../../App/FeatureSet/Dashboard/src/Components/SecurityEvents/SecurityEventsTableColumns";
|
|
6
|
-
import Column from "../../../UI/Components/ModelTable/Column";
|
|
7
|
-
import { getColumnIds } from "../../../UI/Components/ModelTable/ColumnPreference";
|
|
8
|
-
import { getSelectFromColumns } from "../../../UI/Components/ModelTable/SelectFromColumns";
|
|
9
|
-
import FieldType from "../../../UI/Components/Types/FieldType";
|
|
10
|
-
import SecurityEvent from "../../../Models/AnalyticsModels/SecurityEvent";
|
|
11
|
-
import OcsfSeverity from "../../../Types/SecurityEvent/OcsfSeverity";
|
|
12
|
-
import Select from "../../../Types/BaseDatabase/Select";
|
|
13
|
-
import { JSONObject } from "../../../Types/JSON";
|
|
14
|
-
|
|
15
|
-
/*
|
|
16
|
-
* ---------------------------------------------------------------------------
|
|
17
|
-
* The security events table's column set
|
|
18
|
-
* ---------------------------------------------------------------------------
|
|
19
|
-
*
|
|
20
|
-
* The table used to offer seven columns while the detail panel showed twelve
|
|
21
|
-
* fields, so answering "which vendor produced all of these?" meant opening
|
|
22
|
-
* every event one at a time (OneUptime/oneuptime#3399). Every field the detail
|
|
23
|
-
* panel shows is now a column; the seven that were the whole table are still
|
|
24
|
-
* the seven that show by default, and the rest are one click away in the
|
|
25
|
-
* picker.
|
|
26
|
-
*
|
|
27
|
-
* Three classes of mistake are invisible on screen and each is pinned below:
|
|
28
|
-
*
|
|
29
|
-
* - a field name that is not a column on the model. getSelectFromColumns
|
|
30
|
-
* throws a BadDataException for the primary field, which blanks the entire
|
|
31
|
-
* table rather than one cell.
|
|
32
|
-
* - a hidden column marked isNotCustomizable, which would put it in neither
|
|
33
|
-
* the table nor the picker: unreachable.
|
|
34
|
-
* - a column that silently changes the DEFAULT layout, which would reshuffle
|
|
35
|
-
* the table for every viewer who has never opened the picker.
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
afterEach(() => {
|
|
39
|
-
cleanup();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
type TitlesOfFunction = (
|
|
43
|
-
columns: Array<Column<SecurityEvent>>,
|
|
44
|
-
) => Array<string>;
|
|
45
|
-
|
|
46
|
-
const titlesOf: TitlesOfFunction = (
|
|
47
|
-
columns: Array<Column<SecurityEvent>>,
|
|
48
|
-
): Array<string> => {
|
|
49
|
-
return columns.map((column: Column<SecurityEvent>) => {
|
|
50
|
-
return column.title;
|
|
51
|
-
});
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const visibleColumns: Array<Column<SecurityEvent>> =
|
|
55
|
-
securityEventColumns.filter((column: Column<SecurityEvent>) => {
|
|
56
|
-
return !column.isHiddenByDefault;
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
type ColumnByTitleFunction = (title: string) => Column<SecurityEvent>;
|
|
60
|
-
|
|
61
|
-
const columnByTitle: ColumnByTitleFunction = (
|
|
62
|
-
title: string,
|
|
63
|
-
): Column<SecurityEvent> => {
|
|
64
|
-
const column: Column<SecurityEvent> | undefined = securityEventColumns.find(
|
|
65
|
-
(candidate: Column<SecurityEvent>) => {
|
|
66
|
-
return candidate.title === title;
|
|
67
|
-
},
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
if (!column) {
|
|
71
|
-
throw new Error(`No security event column titled "${title}"`);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return column;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
type MakeEventFunction = (data: JSONObject) => SecurityEvent;
|
|
78
|
-
|
|
79
|
-
const makeEvent: MakeEventFunction = (data: JSONObject): SecurityEvent => {
|
|
80
|
-
const event: SecurityEvent = new SecurityEvent();
|
|
81
|
-
|
|
82
|
-
for (const key of Object.keys(data)) {
|
|
83
|
-
(event as unknown as JSONObject)[key] = data[key];
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return event;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
describe("SecurityEventsTable columns - the default layout", () => {
|
|
90
|
-
/*
|
|
91
|
-
* These seven, in this order, are what the table showed before the rest were
|
|
92
|
-
* added. Anything new has to ship hidden, or every existing viewer's table
|
|
93
|
-
* silently rearranges itself.
|
|
94
|
-
*/
|
|
95
|
-
test("shows exactly the seven columns it always did, in the same order", () => {
|
|
96
|
-
expect(titlesOf(visibleColumns)).toEqual([
|
|
97
|
-
"Time",
|
|
98
|
-
"Severity",
|
|
99
|
-
"Event Class",
|
|
100
|
-
"Message",
|
|
101
|
-
"Principal User",
|
|
102
|
-
"Principal Host",
|
|
103
|
-
"Vendor",
|
|
104
|
-
]);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("everything else ships hidden", () => {
|
|
108
|
-
const hidden: Array<Column<SecurityEvent>> = securityEventColumns.filter(
|
|
109
|
-
(column: Column<SecurityEvent>) => {
|
|
110
|
-
return Boolean(column.isHiddenByDefault);
|
|
111
|
-
},
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
expect(hidden.length).toBe(securityEventColumns.length - 7);
|
|
115
|
-
expect(hidden.length).toBeGreaterThan(0);
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
describe("SecurityEventsTable columns - coverage of the detail panel", () => {
|
|
120
|
-
/*
|
|
121
|
-
* The issue's actual complaint: these are the fields the detail panel showed
|
|
122
|
-
* but the picker did not offer. Named one by one rather than counted, so a
|
|
123
|
-
* regression says which one went missing.
|
|
124
|
-
*/
|
|
125
|
-
const requestedInIssue: Array<string> = [
|
|
126
|
-
"Category",
|
|
127
|
-
"Activity",
|
|
128
|
-
"Vendor",
|
|
129
|
-
"Product",
|
|
130
|
-
"Rule Name",
|
|
131
|
-
"Observables",
|
|
132
|
-
"Event UID",
|
|
133
|
-
];
|
|
134
|
-
|
|
135
|
-
test.each(requestedInIssue)("offers a %s column", (title: string) => {
|
|
136
|
-
expect(titlesOf(securityEventColumns)).toContain(title);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
/*
|
|
140
|
-
* The rest of what the detail panel renders. Parity is the point: anything
|
|
141
|
-
* worth reading on one event is worth scanning down the table.
|
|
142
|
-
*/
|
|
143
|
-
const restOfTheDetailPanel: Array<string> = [
|
|
144
|
-
"Time",
|
|
145
|
-
"Severity",
|
|
146
|
-
"Event Class",
|
|
147
|
-
"Status",
|
|
148
|
-
"Message",
|
|
149
|
-
"Rule ID",
|
|
150
|
-
"MITRE Tactics",
|
|
151
|
-
"MITRE Techniques",
|
|
152
|
-
"Principal User",
|
|
153
|
-
"Principal Host",
|
|
154
|
-
"Principal IP",
|
|
155
|
-
"Principal Process",
|
|
156
|
-
"Target User",
|
|
157
|
-
"Target Host",
|
|
158
|
-
"Target IP",
|
|
159
|
-
"Target Port",
|
|
160
|
-
"Target Resource",
|
|
161
|
-
];
|
|
162
|
-
|
|
163
|
-
test.each(restOfTheDetailPanel)(
|
|
164
|
-
"also offers a %s column",
|
|
165
|
-
(title: string) => {
|
|
166
|
-
expect(titlesOf(securityEventColumns)).toContain(title);
|
|
167
|
-
},
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
test("the picker offers materially more than the seven it used to", () => {
|
|
171
|
-
expect(securityEventColumns.length).toBe(
|
|
172
|
-
requestedInIssue.length + restOfTheDetailPanel.length,
|
|
173
|
-
);
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
describe("SecurityEventsTable columns - shape", () => {
|
|
178
|
-
test("every declared field is a real column on the model", () => {
|
|
179
|
-
const model: SecurityEvent = new SecurityEvent();
|
|
180
|
-
|
|
181
|
-
for (const column of securityEventColumns) {
|
|
182
|
-
for (const field of Object.keys(column.field as JSONObject)) {
|
|
183
|
-
expect({
|
|
184
|
-
title: column.title,
|
|
185
|
-
field,
|
|
186
|
-
exists: model.hasColumn(field),
|
|
187
|
-
}).toEqual({ title: column.title, field, exists: true });
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
/*
|
|
193
|
-
* The real check that the above is enough: this is the call the table makes
|
|
194
|
-
* on every fetch, and it throws rather than degrading.
|
|
195
|
-
*/
|
|
196
|
-
test("building the API select does not throw", () => {
|
|
197
|
-
const select: Select<SecurityEvent> = getSelectFromColumns<SecurityEvent>({
|
|
198
|
-
columns: securityEventColumns,
|
|
199
|
-
model: new SecurityEvent(),
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
expect((select as JSONObject)["categoryName"]).toBe(true);
|
|
203
|
-
expect((select as JSONObject)["observables"]).toBe(true);
|
|
204
|
-
expect((select as JSONObject)["eventUid"]).toBe(true);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
test("column ids are unique, so a stored layout cannot confuse two of them", () => {
|
|
208
|
-
const ids: Array<string> =
|
|
209
|
-
getColumnIds<SecurityEvent>(securityEventColumns);
|
|
210
|
-
|
|
211
|
-
expect(new Set(ids).size).toBe(ids.length);
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
test("titles are unique, so the picker's search is unambiguous", () => {
|
|
215
|
-
const titles: Array<string> = titlesOf(securityEventColumns);
|
|
216
|
-
|
|
217
|
-
expect(new Set(titles).size).toBe(titles.length);
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
/*
|
|
221
|
-
* A hidden AND non-customizable column would be in neither the table nor the
|
|
222
|
-
* picker.
|
|
223
|
-
*/
|
|
224
|
-
test("no column is both hidden by default and kept out of the picker", () => {
|
|
225
|
-
for (const column of securityEventColumns) {
|
|
226
|
-
expect({
|
|
227
|
-
title: column.title,
|
|
228
|
-
unreachable: Boolean(
|
|
229
|
-
column.isHiddenByDefault && column.isNotCustomizable,
|
|
230
|
-
),
|
|
231
|
-
}).toEqual({ title: column.title, unreachable: false });
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
/*
|
|
236
|
-
* These columns are the table's own, not the viewer's - "remove" is only for
|
|
237
|
-
* attribute columns, which are added from the picker in the first place.
|
|
238
|
-
*/
|
|
239
|
-
test("no declared column is removable", () => {
|
|
240
|
-
for (const column of securityEventColumns) {
|
|
241
|
-
expect({
|
|
242
|
-
title: column.title,
|
|
243
|
-
removable: Boolean(column.isRemovable),
|
|
244
|
-
}).toEqual({ title: column.title, removable: false });
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
describe("SecurityEventsTable columns - cells", () => {
|
|
250
|
-
test("a text column with no value renders a dash rather than blank", () => {
|
|
251
|
-
expect(columnByTitle("Category").noValueMessage).toBe("-");
|
|
252
|
-
expect(columnByTitle("Rule Name").noValueMessage).toBe("-");
|
|
253
|
-
expect(columnByTitle("Event UID").noValueMessage).toBe("-");
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
test("Observables joins the list into one scannable line", () => {
|
|
257
|
-
const column: Column<SecurityEvent> = columnByTitle("Observables");
|
|
258
|
-
|
|
259
|
-
const { container } = render(
|
|
260
|
-
column.getElement!(
|
|
261
|
-
makeEvent({ observables: ["web-1", "10.0.0.4", "bob@example.com"] }),
|
|
262
|
-
),
|
|
263
|
-
);
|
|
264
|
-
|
|
265
|
-
expect(container.textContent).toBe("web-1, 10.0.0.4, bob@example.com");
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
test("Observables keeps the full list available on hover", () => {
|
|
269
|
-
const column: Column<SecurityEvent> = columnByTitle("Observables");
|
|
270
|
-
|
|
271
|
-
const { container } = render(
|
|
272
|
-
column.getElement!(makeEvent({ observables: ["web-1", "10.0.0.4"] })),
|
|
273
|
-
);
|
|
274
|
-
|
|
275
|
-
expect(container.querySelector("span")).toHaveAttribute(
|
|
276
|
-
"title",
|
|
277
|
-
"web-1, 10.0.0.4",
|
|
278
|
-
);
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
test("an empty array column renders the placeholder, not an empty cell", () => {
|
|
282
|
-
const column: Column<SecurityEvent> = columnByTitle("MITRE Tactics");
|
|
283
|
-
|
|
284
|
-
const { container } = render(
|
|
285
|
-
column.getElement!(makeEvent({ mitreTactics: [] })),
|
|
286
|
-
);
|
|
287
|
-
|
|
288
|
-
expect(container.textContent).toBe("-");
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
test("blank entries inside an array are dropped rather than joined as commas", () => {
|
|
292
|
-
const column: Column<SecurityEvent> = columnByTitle("MITRE Techniques");
|
|
293
|
-
|
|
294
|
-
const { container } = render(
|
|
295
|
-
column.getElement!(
|
|
296
|
-
makeEvent({ mitreTechniques: ["T1110", "", "T1078"] }),
|
|
297
|
-
),
|
|
298
|
-
);
|
|
299
|
-
|
|
300
|
-
expect(container.textContent).toBe("T1110, T1078");
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
test("array columns export the same joined text they render", () => {
|
|
304
|
-
const column: Column<SecurityEvent> = columnByTitle("Observables");
|
|
305
|
-
|
|
306
|
-
expect(
|
|
307
|
-
column.getExportValue!(makeEvent({ observables: ["web-1", "10.0.0.4"] })),
|
|
308
|
-
).toBe("web-1, 10.0.0.4");
|
|
309
|
-
|
|
310
|
-
expect(column.getExportValue!(makeEvent({ observables: [] }))).toBe("");
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
/*
|
|
314
|
-
* ClickHouse cannot meaningfully order by an Array(String), and nothing
|
|
315
|
-
* between the header and the query builder would reject the attempt.
|
|
316
|
-
*/
|
|
317
|
-
test("array columns are not sortable", () => {
|
|
318
|
-
expect(columnByTitle("Observables").disableSort).toBe(true);
|
|
319
|
-
expect(columnByTitle("MITRE Tactics").disableSort).toBe(true);
|
|
320
|
-
expect(columnByTitle("MITRE Techniques").disableSort).toBe(true);
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
/*
|
|
324
|
-
* targetPort is non-nullable with a 0 default, so 0 means "the source did
|
|
325
|
-
* not say" far more often than it means port zero.
|
|
326
|
-
*/
|
|
327
|
-
test("Target Port renders a dash when the source did not say", () => {
|
|
328
|
-
const column: Column<SecurityEvent> = columnByTitle("Target Port");
|
|
329
|
-
|
|
330
|
-
const { container } = render(
|
|
331
|
-
column.getElement!(makeEvent({ targetPort: 0 })),
|
|
332
|
-
);
|
|
333
|
-
|
|
334
|
-
expect(container.textContent).toBe("-");
|
|
335
|
-
expect(column.getExportValue!(makeEvent({ targetPort: 0 }))).toBe("");
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
test("Target Port renders a real port", () => {
|
|
339
|
-
const column: Column<SecurityEvent> = columnByTitle("Target Port");
|
|
340
|
-
|
|
341
|
-
const { container } = render(
|
|
342
|
-
column.getElement!(makeEvent({ targetPort: 443 })),
|
|
343
|
-
);
|
|
344
|
-
|
|
345
|
-
expect(container.textContent).toBe("443");
|
|
346
|
-
expect(column.getExportValue!(makeEvent({ targetPort: 443 }))).toBe("443");
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
test("Severity still renders its pill", () => {
|
|
350
|
-
const column: Column<SecurityEvent> = columnByTitle("Severity");
|
|
351
|
-
|
|
352
|
-
const { container } = render(
|
|
353
|
-
column.getElement!(makeEvent({ severityName: OcsfSeverity.Critical })),
|
|
354
|
-
);
|
|
355
|
-
|
|
356
|
-
expect(container.textContent).toContain("Critical");
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
test("Time renders a relative and an absolute reading", () => {
|
|
360
|
-
const column: Column<SecurityEvent> = columnByTitle("Time");
|
|
361
|
-
|
|
362
|
-
const { container } = render(
|
|
363
|
-
column.getElement!(makeEvent({ time: new Date("2024-03-01T10:00:00Z") })),
|
|
364
|
-
);
|
|
365
|
-
|
|
366
|
-
expect(container.textContent).toContain("2024");
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
test("Time with nothing to show renders the placeholder", () => {
|
|
370
|
-
const column: Column<SecurityEvent> = columnByTitle("Time");
|
|
371
|
-
|
|
372
|
-
const { container } = render(column.getElement!(makeEvent({})));
|
|
373
|
-
|
|
374
|
-
expect(container.textContent).toBe("-");
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
test("long free-text columns are typed as long text so they wrap", () => {
|
|
378
|
-
expect(columnByTitle("Message").type).toBe(FieldType.LongText);
|
|
379
|
-
expect(columnByTitle("Principal Process").type).toBe(FieldType.LongText);
|
|
380
|
-
expect(columnByTitle("Target Resource").type).toBe(FieldType.LongText);
|
|
381
|
-
});
|
|
382
|
-
});
|