From 3ba6e39ac9e00ed3d48ad0eefc0e9027f67dfb0f Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Thu, 12 Mar 2026 13:50:54 +0100 Subject: [PATCH 1/3] Refactor Notification Policy and Rules Saved Object Services - Introduced `NotificationPolicySavedObjectsClientToken` and `RuleSavedObjectsClientToken` for pre-configured SavedObjects clients with hidden types. - Updated `NotificationPolicySavedObjectService` and `RulesSavedObjectService` to use injected clients instead of factories. - Simplified service instantiation in `bind_services.ts` to enhance dependency injection. - Adjusted integration tests to reflect changes in service construction and client usage. This refactor improves the clarity and maintainability of the code by centralizing client configuration and reducing boilerplate in service implementations. --- .../integration_tests/dispatcher.test.ts | 16 +++++++++--- ...cation_policy_saved_object_service.mock.ts | 3 +-- ...otification_policy_saved_object_service.ts | 15 +++-------- .../tokens.ts | 8 ++++++ .../rules_saved_object_service.mock.ts | 6 +---- .../rules_saved_object_service.ts | 15 +++-------- .../rules_saved_object_service/tokens.ts | 8 ++++++ .../alerting_v2/server/setup/bind_services.ts | 26 ++++++++++++++++--- 8 files changed, 62 insertions(+), 35 deletions(-) diff --git a/x-pack/platform/plugins/shared/alerting_v2/server/lib/dispatcher/integration_tests/dispatcher.test.ts b/x-pack/platform/plugins/shared/alerting_v2/server/lib/dispatcher/integration_tests/dispatcher.test.ts index 569bf107a3ce1..9e140b65000f1 100644 --- a/x-pack/platform/plugins/shared/alerting_v2/server/lib/dispatcher/integration_tests/dispatcher.test.ts +++ b/x-pack/platform/plugins/shared/alerting_v2/server/lib/dispatcher/integration_tests/dispatcher.test.ts @@ -7,6 +7,7 @@ import type { TestElasticsearchUtils, TestKibanaUtils } from '@kbn/core-test-helpers-kbn-server'; import type { ElasticsearchClient } from '@kbn/core/server'; +import type { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-plugin/server'; import type { WorkflowsServerPluginSetup } from '@kbn/workflows-management-plugin/server'; import { ALERT_ACTIONS_DATA_STREAM, type AlertAction } from '../../../resources/alert_actions'; import { ALERT_EVENTS_DATA_STREAM, type AlertEvent } from '../../../resources/alert_events'; @@ -14,6 +15,10 @@ import type { RuleSavedObjectAttributes, NotificationPolicySavedObjectAttributes, } from '../../../saved_objects'; +import { + RULE_SAVED_OBJECT_TYPE, + NOTIFICATION_POLICY_SAVED_OBJECT_TYPE, +} from '../../../saved_objects'; import type { LoggerServiceContract } from '../../services/logger_service/logger_service'; import { createLoggerService } from '../../services/logger_service/logger_service.mock'; import { NotificationPolicySavedObjectService } from '../../services/notification_policy_saved_object_service/notification_policy_saved_object_service'; @@ -359,12 +364,17 @@ describe('DispatcherService integration tests', () => { esClient = kibanaServer.coreStart.elasticsearch.client.asInternalUser; rulesSoService = new RulesSavedObjectService( - (opts) => kibanaServer.coreStart.savedObjects.getUnsafeInternalClient(opts), + kibanaServer.coreStart.savedObjects.getUnsafeInternalClient({ + includedHiddenTypes: [RULE_SAVED_OBJECT_TYPE], + }), undefined as unknown as SpacesPluginStart ); npSoService = new NotificationPolicySavedObjectService( - (opts) => kibanaServer.coreStart.savedObjects.getUnsafeInternalClient(opts), - undefined as unknown as SpacesPluginStart + kibanaServer.coreStart.savedObjects.getUnsafeInternalClient({ + includedHiddenTypes: [NOTIFICATION_POLICY_SAVED_OBJECT_TYPE], + }), + undefined as unknown as SpacesPluginStart, + undefined as unknown as EncryptedSavedObjectsClient ); await waitForDataStreamsReady(esClient, [ALERT_EVENTS_DATA_STREAM, ALERT_ACTIONS_DATA_STREAM]); diff --git a/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/notification_policy_saved_object_service/notification_policy_saved_object_service.mock.ts b/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/notification_policy_saved_object_service/notification_policy_saved_object_service.mock.ts index d22626870b986..7bd707d37da2b 100644 --- a/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/notification_policy_saved_object_service/notification_policy_saved_object_service.mock.ts +++ b/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/notification_policy_saved_object_service/notification_policy_saved_object_service.mock.ts @@ -24,12 +24,11 @@ export function createNotificationPolicySavedObjectService(): { mockBulkGetDecryptedByIds: jest.SpyInstance; } { const mockSavedObjectsClient = savedObjectsClientMock.create(); - const mockSavedObjectsClientFactory = jest.fn().mockReturnValue(mockSavedObjectsClient); const mockSpaces = spacesMock.createStart(); const mockEncryptedSavedObjectsClient = createMockEncryptedSavedObjectsClient(); const notificationPolicySavedObjectService = new NotificationPolicySavedObjectService( - mockSavedObjectsClientFactory, + mockSavedObjectsClient, mockSpaces, mockEncryptedSavedObjectsClient ); diff --git a/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/notification_policy_saved_object_service/notification_policy_saved_object_service.ts b/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/notification_policy_saved_object_service/notification_policy_saved_object_service.ts index efcf198ae594e..814740f5af484 100644 --- a/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/notification_policy_saved_object_service/notification_policy_saved_object_service.ts +++ b/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/notification_policy_saved_object_service/notification_policy_saved_object_service.ts @@ -6,8 +6,6 @@ */ import { PluginStart } from '@kbn/core-di'; -import type { ISavedObjectsClientFactory } from '@kbn/core-di-server'; -import { SavedObjectsClientFactory } from '@kbn/core-di-server'; import type { SavedObjectsClientContract } from '@kbn/core/server'; import { SavedObjectsUtils } from '@kbn/core/server'; import type { SavedObjectError } from '@kbn/core/types'; @@ -20,6 +18,7 @@ import type { NotificationPolicySavedObjectAttributes } from '../../../saved_obj import { NOTIFICATION_POLICY_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import type { AlertingServerStartDependencies } from '../../../types'; import { spaceIdToNamespace } from '../../space_id_to_namespace'; +import { NotificationPolicySavedObjectsClientToken } from './tokens'; export type NotificationPolicySavedObjectBulkGetItem = | { @@ -66,20 +65,14 @@ export interface NotificationPolicySavedObjectServiceContract { export class NotificationPolicySavedObjectService implements NotificationPolicySavedObjectServiceContract { - private readonly client: SavedObjectsClientContract; - constructor( - @inject(SavedObjectsClientFactory) - private readonly savedObjectsClientFactory: ISavedObjectsClientFactory, + @inject(NotificationPolicySavedObjectsClientToken) + private readonly client: SavedObjectsClientContract, @inject(PluginStart('spaces')) private readonly spaces: SpacesPluginStart, @inject(EncryptedSavedObjectsClientToken) private readonly encryptedSavedObjectsClient: EncryptedSavedObjectsClient - ) { - this.client = this.savedObjectsClientFactory({ - includedHiddenTypes: [NOTIFICATION_POLICY_SAVED_OBJECT_TYPE], - }); - } + ) {} public async create({ attrs, diff --git a/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/notification_policy_saved_object_service/tokens.ts b/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/notification_policy_saved_object_service/tokens.ts index 834c20b521404..c4b54b37fc6f9 100644 --- a/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/notification_policy_saved_object_service/tokens.ts +++ b/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/notification_policy_saved_object_service/tokens.ts @@ -5,9 +5,17 @@ * 2.0. */ +import type { SavedObjectsClientContract } from '@kbn/core/server'; import type { ServiceIdentifier } from 'inversify'; import type { NotificationPolicySavedObjectServiceContract } from './notification_policy_saved_object_service'; +/** + * Pre-configured SavedObjects client with hidden types for notification policies + */ +export const NotificationPolicySavedObjectsClientToken = Symbol.for( + 'alerting_v2.NotificationPolicySavedObjectsClient' +) as ServiceIdentifier; + /** * NotificationPolicySavedObjectService scoped to the current request */ diff --git a/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/rules_saved_object_service/rules_saved_object_service.mock.ts b/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/rules_saved_object_service/rules_saved_object_service.mock.ts index 5fca4852e4a83..dd14c3396e305 100644 --- a/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/rules_saved_object_service/rules_saved_object_service.mock.ts +++ b/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/rules_saved_object_service/rules_saved_object_service.mock.ts @@ -15,13 +15,9 @@ export function createRulesSavedObjectService(): { mockSavedObjectsClient: jest.Mocked; } { const mockSavedObjectsClient = savedObjectsClientMock.create(); - const mockSavedObjectsClientFactory = jest.fn().mockReturnValue(mockSavedObjectsClient); const mockSpaces = spacesMock.createStart(); - const rulesSavedObjectService = new RulesSavedObjectService( - mockSavedObjectsClientFactory, - mockSpaces - ); + const rulesSavedObjectService = new RulesSavedObjectService(mockSavedObjectsClient, mockSpaces); return { rulesSavedObjectService, mockSavedObjectsClient }; } diff --git a/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/rules_saved_object_service/rules_saved_object_service.ts b/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/rules_saved_object_service/rules_saved_object_service.ts index b15b09dc54b83..df3443bba9ecc 100644 --- a/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/rules_saved_object_service/rules_saved_object_service.ts +++ b/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/rules_saved_object_service/rules_saved_object_service.ts @@ -7,8 +7,6 @@ import { PluginStart } from '@kbn/core-di'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/server'; -import type { ISavedObjectsClientFactory } from '@kbn/core-di-server'; -import { SavedObjectsClientFactory } from '@kbn/core-di-server'; import { inject, injectable } from 'inversify'; import type { SavedObjectsClientContract } from '@kbn/core/server'; import { SavedObjectsUtils } from '@kbn/core/server'; @@ -17,6 +15,7 @@ import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import type { RuleSavedObjectAttributes } from '../../../saved_objects'; import type { AlertingServerStartDependencies } from '../../../types'; import { spaceIdToNamespace } from '../../space_id_to_namespace'; +import { RuleSavedObjectsClientToken } from './tokens'; export type RulesSavedObjectsBulkGetResultItem = | { @@ -46,18 +45,12 @@ export interface RulesSavedObjectServiceContract { @injectable() export class RulesSavedObjectService implements RulesSavedObjectServiceContract { - private readonly client: SavedObjectsClientContract; - constructor( - @inject(SavedObjectsClientFactory) - private readonly savedObjectsClientFactory: ISavedObjectsClientFactory, + @inject(RuleSavedObjectsClientToken) + private readonly client: SavedObjectsClientContract, @inject(PluginStart('spaces')) private readonly spaces: SpacesPluginStart - ) { - this.client = this.savedObjectsClientFactory({ - includedHiddenTypes: [RULE_SAVED_OBJECT_TYPE], - }); - } + ) {} public async create({ attrs, id, diff --git a/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/rules_saved_object_service/tokens.ts b/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/rules_saved_object_service/tokens.ts index 4c984cc3c0458..b3498feaae375 100644 --- a/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/rules_saved_object_service/tokens.ts +++ b/x-pack/platform/plugins/shared/alerting_v2/server/lib/services/rules_saved_object_service/tokens.ts @@ -5,9 +5,17 @@ * 2.0. */ +import type { SavedObjectsClientContract } from '@kbn/core/server'; import type { ServiceIdentifier } from 'inversify'; import type { RulesSavedObjectServiceContract } from './rules_saved_object_service'; +/** + * Pre-configured SavedObjects client with hidden types for rules + */ +export const RuleSavedObjectsClientToken = Symbol.for( + 'alerting_v2.RuleSavedObjectsClient' +) as ServiceIdentifier; + /** * RulesSavedObjectService scoped to the current request */ diff --git a/x-pack/platform/plugins/shared/alerting_v2/server/setup/bind_services.ts b/x-pack/platform/plugins/shared/alerting_v2/server/setup/bind_services.ts index 08946c1a8f80b..9b9cf0824efef 100644 --- a/x-pack/platform/plugins/shared/alerting_v2/server/setup/bind_services.ts +++ b/x-pack/platform/plugins/shared/alerting_v2/server/setup/bind_services.ts @@ -6,7 +6,7 @@ */ import { PluginSetup, PluginStart } from '@kbn/core-di'; -import { CoreStart, Request } from '@kbn/core-di-server'; +import { CoreStart, Request, SavedObjectsClientFactory } from '@kbn/core-di-server'; import type { ContainerModuleLoadOptions } from 'inversify'; import { AlertActionsClient } from '../lib/alert_actions_client'; import { DirectorService } from '../lib/director/director'; @@ -23,6 +23,7 @@ import { EsServiceInternalToken, EsServiceScopedToken } from '../lib/services/es import { LoggerService, LoggerServiceToken } from '../lib/services/logger_service/logger_service'; import { NotificationPolicySavedObjectService } from '../lib/services/notification_policy_saved_object_service/notification_policy_saved_object_service'; import { + NotificationPolicySavedObjectsClientToken, NotificationPolicySavedObjectServiceInternalToken, NotificationPolicySavedObjectServiceScopedToken, } from '../lib/services/notification_policy_saved_object_service/tokens'; @@ -36,6 +37,7 @@ import { AlertingRetryService } from '../lib/services/retry_service'; import { RetryServiceToken } from '../lib/services/retry_service/tokens'; import { RulesSavedObjectService } from '../lib/services/rules_saved_object_service/rules_saved_object_service'; import { + RuleSavedObjectsClientToken, RulesSavedObjectServiceInternalToken, RulesSavedObjectServiceScopedToken, } from '../lib/services/rules_saved_object_service/tokens'; @@ -90,6 +92,14 @@ export function bindServices({ bind }: ContainerModuleLoadOptions) { }) ); + bind(RuleSavedObjectsClientToken) + .toResolvedValue( + (savedObjectsClientFactory) => + savedObjectsClientFactory({ includedHiddenTypes: [RULE_SAVED_OBJECT_TYPE] }), + [SavedObjectsClientFactory] + ) + .inRequestScope(); + bind(RulesSavedObjectService).toSelf().inRequestScope(); bind(RulesSavedObjectServiceScopedToken).toService(RulesSavedObjectService); bind(RulesSavedObjectServiceInternalToken) @@ -97,7 +107,7 @@ export function bindServices({ bind }: ContainerModuleLoadOptions) { const savedObjects = get(CoreStart('savedObjects')); const spaces = get(PluginStart('spaces')); const internalClient = savedObjects.createInternalRepository([RULE_SAVED_OBJECT_TYPE]); - return new RulesSavedObjectService(() => internalClient, spaces); + return new RulesSavedObjectService(internalClient, spaces); }) .inSingletonScope(); @@ -112,6 +122,16 @@ export function bindServices({ bind }: ContainerModuleLoadOptions) { }) .inSingletonScope(); + bind(NotificationPolicySavedObjectsClientToken) + .toResolvedValue( + (savedObjectsClientFactory) => + savedObjectsClientFactory({ + includedHiddenTypes: [NOTIFICATION_POLICY_SAVED_OBJECT_TYPE], + }), + [SavedObjectsClientFactory] + ) + .inRequestScope(); + bind(NotificationPolicySavedObjectService).toSelf().inRequestScope(); bind(NotificationPolicySavedObjectServiceScopedToken).toService( NotificationPolicySavedObjectService @@ -124,7 +144,7 @@ export function bindServices({ bind }: ContainerModuleLoadOptions) { NOTIFICATION_POLICY_SAVED_OBJECT_TYPE, ]); const esoClient = get(EncryptedSavedObjectsClientToken); - return new NotificationPolicySavedObjectService(() => internalClient, spaces, esoClient); + return new NotificationPolicySavedObjectService(internalClient, spaces, esoClient); }) .inSingletonScope(); From 6d5c2908fb18d7a5dbd274df3d58ac04da7a5fb6 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Thu, 12 Mar 2026 14:00:18 +0100 Subject: [PATCH 2/3] fix: Update ESO_TYPES_COUNT to include alerting_notification_policy The alerting_v2 branch introduced a new encrypted saved object type (alerting_notification_policy) but the ESO_TYPES_COUNT constant was not incremented from 20 to 21. Made-with: Cursor --- .../integration_tests/ci_checks/check_registered_types.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/encrypted_saved_objects/integration_tests/ci_checks/check_registered_types.test.ts b/x-pack/platform/plugins/shared/encrypted_saved_objects/integration_tests/ci_checks/check_registered_types.test.ts index c16f10cb8c1d2..2740193e0db45 100644 --- a/x-pack/platform/plugins/shared/encrypted_saved_objects/integration_tests/ci_checks/check_registered_types.test.ts +++ b/x-pack/platform/plugins/shared/encrypted_saved_objects/integration_tests/ci_checks/check_registered_types.test.ts @@ -20,7 +20,7 @@ import type { EncryptedSavedObjectsService } from '../../server/crypto'; import * as EncryptedSavedObjectsModule from '../../server/saved_objects'; // This will only change if new ESOs are introduced. This number should never get smaller. -export const ESO_TYPES_COUNT = 20 as const; +export const ESO_TYPES_COUNT = 21 as const; describe('checking changes on all registered encrypted SO types', () => { let esServer: TestElasticsearchUtils; From 3ef325ba82a6471e35c9e655c6dfdb4d48dca647 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Thu, 12 Mar 2026 14:52:15 +0100 Subject: [PATCH 3/3] update tests --- .../saved-objects/server-internal/src/object_types/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/packages/saved-objects/server-internal/src/object_types/index.ts b/src/core/packages/saved-objects/server-internal/src/object_types/index.ts index 8e90231cec665..3e98804eab35d 100644 --- a/src/core/packages/saved-objects/server-internal/src/object_types/index.ts +++ b/src/core/packages/saved-objects/server-internal/src/object_types/index.ts @@ -11,4 +11,4 @@ export { registerCoreObjectTypes } from './registration'; // set minimum number of registered saved objects to ensure no object types are removed after 8.8 // declared in internal implementation explicitly to prevent unintended changes. -export const SAVED_OBJECT_TYPES_COUNT = 149 as const; +export const SAVED_OBJECT_TYPES_COUNT = 151 as const;