From f479dff908ceb200aaee64450bcd0d8239747127 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Sat, 22 Jul 2023 17:54:35 +0300 Subject: [PATCH] Allow to disable system actions --- .../server/action_type_registry.test.ts | 35 ++--- .../actions/server/action_type_registry.ts | 13 +- .../server/create_execute_function.test.ts | 123 ++++++++++-------- 3 files changed, 94 insertions(+), 77 deletions(-) diff --git a/x-pack/plugins/actions/server/action_type_registry.test.ts b/x-pack/plugins/actions/server/action_type_registry.test.ts index 915f5ed047052a..54a50b694782eb 100644 --- a/x-pack/plugins/actions/server/action_type_registry.test.ts +++ b/x-pack/plugins/actions/server/action_type_registry.test.ts @@ -49,10 +49,10 @@ describe('actionTypeRegistry', () => { isSystemAction: false, }, { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', config: {}, - id: 'system-connector-.cases', - name: 'System action: .cases', + id: 'system-connector-test.system-action', + name: 'System action: test.system-action', secrets: {}, isPreconfigured: false, isDeprecated: false, @@ -393,7 +393,7 @@ describe('actionTypeRegistry', () => { const actionTypeRegistry = new ActionTypeRegistry(actionTypeRegistryParams); actionTypeRegistry.register({ - id: '.cases', + id: 'test.system-action', name: 'Cases', minimumLicenseRequired: 'platinum', supportedFeatureIds: ['alerting'], @@ -410,7 +410,7 @@ describe('actionTypeRegistry', () => { expect(actionTypes).toEqual([ { - id: '.cases', + id: 'test.system-action', name: 'Cases', enabled: true, enabledInConfig: true, @@ -497,13 +497,16 @@ describe('actionTypeRegistry', () => { expect(actionTypeRegistry.isActionExecutable('my-slack1', 'foo')).toEqual(true); }); - test('should return true when isActionTypeEnabled is false and isLicenseValidForActionType is true and it has system connectors', async () => { + test('should return false when isActionTypeEnabled is false and isLicenseValidForActionType is true and it has system connectors', async () => { mockedActionsConfig.isActionTypeEnabled.mockReturnValue(false); mockedLicenseState.isLicenseValidForActionType.mockReturnValue({ isValid: true }); expect( - actionTypeRegistry.isActionExecutable('system-connector-.cases', 'system-action-type') - ).toEqual(true); + actionTypeRegistry.isActionExecutable( + 'system-connector-test.system-action', + 'system-action-type' + ) + ).toEqual(false); }); test('should call isLicenseValidForActionType of the license state with notifyUsage false by default', async () => { @@ -662,7 +665,7 @@ describe('actionTypeRegistry', () => { const registry = new ActionTypeRegistry(actionTypeRegistryParams); registry.register({ - id: '.cases', + id: 'test.system-action', name: 'Cases', minimumLicenseRequired: 'platinum', supportedFeatureIds: ['alerting'], @@ -675,7 +678,7 @@ describe('actionTypeRegistry', () => { executor, }); - const result = registry.isSystemActionType('.cases'); + const result = registry.isSystemActionType('test.system-action'); expect(result).toBe(true); }); @@ -720,7 +723,7 @@ describe('actionTypeRegistry', () => { const registry = new ActionTypeRegistry(actionTypeRegistryParams); registry.register({ - id: '.cases', + id: 'test.system-action', name: 'Cases', minimumLicenseRequired: 'platinum', supportedFeatureIds: ['alerting'], @@ -734,7 +737,7 @@ describe('actionTypeRegistry', () => { executor, }); - const result = registry.getSystemActionKibanaPrivileges('.cases'); + const result = registry.getSystemActionKibanaPrivileges('test.system-action'); expect(result).toEqual(['test/create']); }); @@ -742,7 +745,7 @@ describe('actionTypeRegistry', () => { const registry = new ActionTypeRegistry(actionTypeRegistryParams); registry.register({ - id: '.cases', + id: 'test.system-action', name: 'Cases', minimumLicenseRequired: 'platinum', supportedFeatureIds: ['alerting'], @@ -755,7 +758,7 @@ describe('actionTypeRegistry', () => { executor, }); - const result = registry.getSystemActionKibanaPrivileges('.cases'); + const result = registry.getSystemActionKibanaPrivileges('test.system-action'); expect(result).toEqual([]); }); @@ -784,7 +787,7 @@ describe('actionTypeRegistry', () => { const getKibanaPrivileges = jest.fn().mockReturnValue(['test/create']); registry.register({ - id: '.cases', + id: 'test.system-action', name: 'Cases', minimumLicenseRequired: 'platinum', supportedFeatureIds: ['alerting'], @@ -798,7 +801,7 @@ describe('actionTypeRegistry', () => { executor, }); - registry.getSystemActionKibanaPrivileges('.cases', { foo: 'bar' }); + registry.getSystemActionKibanaPrivileges('test.system-action', { foo: 'bar' }); expect(getKibanaPrivileges).toHaveBeenCalledWith({ params: { foo: 'bar' } }); }); }); diff --git a/x-pack/plugins/actions/server/action_type_registry.ts b/x-pack/plugins/actions/server/action_type_registry.ts index 5d96b0d6b9761a..b3046909975a4f 100644 --- a/x-pack/plugins/actions/server/action_type_registry.ts +++ b/x-pack/plugins/actions/server/action_type_registry.ts @@ -79,7 +79,10 @@ export class ActionTypeRegistry { } /** - * Returns true if action type is enabled or it is an in memory action type. + * Returns true if action type is enabled or it is a preconfigured action type + * It is possible for to disable an action type but use a preconfigured action + * of action type the disabled one. This does not apply to system actions. + * It should be possible to disable a system action type. */ public isActionExecutable( actionId: string, @@ -87,11 +90,13 @@ export class ActionTypeRegistry { options: { notifyUsage: boolean } = { notifyUsage: false } ) { const actionTypeEnabled = this.isActionTypeEnabled(actionTypeId, options); + const inMemoryConnector = this.inMemoryConnectors.find( + (connector) => connector.id === actionId + ); + return ( actionTypeEnabled || - (!actionTypeEnabled && - this.inMemoryConnectors.find((inMemoryConnector) => inMemoryConnector.id === actionId) !== - undefined) + (!actionTypeEnabled && inMemoryConnector !== undefined && inMemoryConnector.isPreconfigured) ); } diff --git a/x-pack/plugins/actions/server/create_execute_function.test.ts b/x-pack/plugins/actions/server/create_execute_function.test.ts index 75a1ecf333311a..fae2ca6c0f9d96 100644 --- a/x-pack/plugins/actions/server/create_execute_function.test.ts +++ b/x-pack/plugins/actions/server/create_execute_function.test.ts @@ -329,10 +329,10 @@ describe('execute()', () => { isESOCanEncrypt: true, inMemoryConnectors: [ { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', config: {}, - id: 'system-connector-.cases', - name: 'System action: .cases', + id: 'system-connector-test.system-action', + name: 'System action: test.system-action', secrets: {}, isPreconfigured: false, isDeprecated: false, @@ -346,7 +346,7 @@ describe('execute()', () => { id: '123', type: 'action', attributes: { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', }, references: [], }); @@ -359,11 +359,11 @@ describe('execute()', () => { }); await executeFn(savedObjectsClient, { - id: 'system-connector-.cases', + id: 'system-connector-test.system-action', params: { baz: false }, spaceId: 'default', executionId: 'system-connector-.casesabc', - apiKey: Buffer.from('system-connector-.cases:abc').toString('base64'), + apiKey: Buffer.from('system-connector-test.system-action:abc').toString('base64'), source: asSavedObjectExecutionSource(source), }); @@ -379,7 +379,7 @@ describe('execute()', () => { "actions", ], "state": Object {}, - "taskType": "actions:.cases", + "taskType": "actions:test.system-action", }, ] `); @@ -387,11 +387,11 @@ describe('execute()', () => { expect(savedObjectsClient.create).toHaveBeenCalledWith( 'action_task_params', { - actionId: 'system-connector-.cases', + actionId: 'system-connector-test.system-action', params: { baz: false }, executionId: 'system-connector-.casesabc', source: 'SAVED_OBJECT', - apiKey: Buffer.from('system-connector-.cases:abc').toString('base64'), + apiKey: Buffer.from('system-connector-test.system-action:abc').toString('base64'), }, { references: [ @@ -513,10 +513,10 @@ describe('execute()', () => { isESOCanEncrypt: true, inMemoryConnectors: [ { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', config: {}, - id: 'system-connector-.cases', - name: 'System action: .cases', + id: 'system-connector-test.system-action', + name: 'System action: test.system-action', secrets: {}, isPreconfigured: false, isDeprecated: false, @@ -530,7 +530,7 @@ describe('execute()', () => { id: '123', type: 'action', attributes: { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', }, references: [], }); @@ -541,10 +541,10 @@ describe('execute()', () => { references: [], }); await executeFn(savedObjectsClient, { - id: 'system-connector-.cases', + id: 'system-connector-test.system-action', params: { baz: false }, spaceId: 'default', - apiKey: Buffer.from('system-connector-.cases:abc').toString('base64'), + apiKey: Buffer.from('system-connector-test.system-action:abc').toString('base64'), source: asSavedObjectExecutionSource(source), executionId: 'system-connector-.casesabc', relatedSavedObjects: [ @@ -568,7 +568,7 @@ describe('execute()', () => { "actions", ], "state": Object {}, - "taskType": "actions:.cases", + "taskType": "actions:test.system-action", }, ] `); @@ -576,9 +576,9 @@ describe('execute()', () => { expect(savedObjectsClient.create).toHaveBeenCalledWith( 'action_task_params', { - actionId: 'system-connector-.cases', + actionId: 'system-connector-test.system-action', params: { baz: false }, - apiKey: Buffer.from('system-connector-.cases:abc').toString('base64'), + apiKey: Buffer.from('system-connector-test.system-action:abc').toString('base64'), executionId: 'system-connector-.casesabc', source: 'SAVED_OBJECT', relatedSavedObjects: [ @@ -738,7 +738,7 @@ describe('execute()', () => { expect(mockedActionTypeRegistry.ensureActionTypeEnabled).not.toHaveBeenCalled(); }); - test('should skip ensure action type if action type is system action and license is valid', async () => { + test('should ensure if a system action type is enabled', async () => { const mockedActionTypeRegistry = actionTypeRegistryMock.create(); const executeFn = createExecutionEnqueuerFunction({ taskManager: mockTaskManager, @@ -746,10 +746,10 @@ describe('execute()', () => { actionTypeRegistry: mockedActionTypeRegistry, inMemoryConnectors: [ { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', config: {}, - id: 'system-connector-.cases', - name: 'System action: .cases', + id: 'system-connector-test.system-action', + name: 'System action: test.system-action', secrets: {}, isPreconfigured: false, isDeprecated: false, @@ -757,15 +757,20 @@ describe('execute()', () => { }, ], }); - mockedActionTypeRegistry.isActionExecutable.mockImplementation(() => true); + + mockedActionTypeRegistry.ensureActionTypeEnabled.mockImplementation(() => { + throw new Error('Fail'); + }); + savedObjectsClient.get.mockResolvedValueOnce({ id: '123', type: 'action', attributes: { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', }, references: [], }); + savedObjectsClient.create.mockResolvedValueOnce({ id: '234', type: 'action_task_params', @@ -773,16 +778,20 @@ describe('execute()', () => { references: [], }); - await executeFn(savedObjectsClient, { - id: 'system-connector-.case', - params: { baz: false }, - spaceId: 'default', - executionId: 'system-connector-.caseabc', - apiKey: null, - source: asHttpRequestExecutionSource(request), - }); + await expect( + executeFn(savedObjectsClient, { + id: 'system-connector-test.system-action', + params: { baz: false }, + spaceId: 'default', + executionId: 'system-connector-.test.system-action-abc', + apiKey: null, + source: asHttpRequestExecutionSource(request), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"Fail"`); - expect(mockedActionTypeRegistry.ensureActionTypeEnabled).not.toHaveBeenCalled(); + expect(mockedActionTypeRegistry.ensureActionTypeEnabled).toHaveBeenCalledWith( + 'test.system-action' + ); }); }); @@ -1155,10 +1164,10 @@ describe('bulkExecute()', () => { isESOCanEncrypt: true, inMemoryConnectors: [ { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', config: {}, - id: 'system-connector-.cases', - name: 'System action: .cases', + id: 'system-connector-test.system-action', + name: 'System action: test.system-action', secrets: {}, isPreconfigured: false, isDeprecated: false, @@ -1174,7 +1183,7 @@ describe('bulkExecute()', () => { id: '123', type: 'action', attributes: { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', }, references: [], }, @@ -1186,7 +1195,7 @@ describe('bulkExecute()', () => { id: '234', type: 'action_task_params', attributes: { - actionId: 'system-connector-.cases', + actionId: 'system-connector-test.system-action', }, references: [], }, @@ -1194,11 +1203,11 @@ describe('bulkExecute()', () => { }); await executeFn(savedObjectsClient, [ { - id: 'system-connector-.cases', + id: 'system-connector-test.system-action', params: { baz: false }, spaceId: 'default', executionId: 'system-connector-.casesabc', - apiKey: Buffer.from('system-connector-.cases:abc').toString('base64'), + apiKey: Buffer.from('system-connector-test.system-action:abc').toString('base64'), source: asSavedObjectExecutionSource(source), }, ]); @@ -1215,7 +1224,7 @@ describe('bulkExecute()', () => { "actions", ], "state": Object {}, - "taskType": "actions:.cases", + "taskType": "actions:test.system-action", }, ], ] @@ -1226,11 +1235,11 @@ describe('bulkExecute()', () => { { type: 'action_task_params', attributes: { - actionId: 'system-connector-.cases', + actionId: 'system-connector-test.system-action', params: { baz: false }, executionId: 'system-connector-.casesabc', source: 'SAVED_OBJECT', - apiKey: Buffer.from('system-connector-.cases:abc').toString('base64'), + apiKey: Buffer.from('system-connector-test.system-action:abc').toString('base64'), }, references: [ { @@ -1370,10 +1379,10 @@ describe('bulkExecute()', () => { isESOCanEncrypt: true, inMemoryConnectors: [ { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', config: {}, - id: 'system-connector-.cases', - name: 'System action: .cases', + id: 'system-connector-test.system-action', + name: 'System action: test.system-action', secrets: {}, isPreconfigured: false, isDeprecated: false, @@ -1389,7 +1398,7 @@ describe('bulkExecute()', () => { id: '123', type: 'action', attributes: { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', }, references: [], }, @@ -1401,7 +1410,7 @@ describe('bulkExecute()', () => { id: '234', type: 'action_task_params', attributes: { - actionId: 'system-connector-.cases', + actionId: 'system-connector-test.system-action', }, references: [], }, @@ -1409,10 +1418,10 @@ describe('bulkExecute()', () => { }); await executeFn(savedObjectsClient, [ { - id: 'system-connector-.cases', + id: 'system-connector-test.system-action', params: { baz: false }, spaceId: 'default', - apiKey: Buffer.from('system-connector-.cases:abc').toString('base64'), + apiKey: Buffer.from('system-connector-test.system-action:abc').toString('base64'), source: asSavedObjectExecutionSource(source), executionId: 'system-connector-.casesabc', relatedSavedObjects: [ @@ -1438,7 +1447,7 @@ describe('bulkExecute()', () => { "actions", ], "state": Object {}, - "taskType": "actions:.cases", + "taskType": "actions:test.system-action", }, ], ] @@ -1449,9 +1458,9 @@ describe('bulkExecute()', () => { { type: 'action_task_params', attributes: { - actionId: 'system-connector-.cases', + actionId: 'system-connector-test.system-action', params: { baz: false }, - apiKey: Buffer.from('system-connector-.cases:abc').toString('base64'), + apiKey: Buffer.from('system-connector-test.system-action:abc').toString('base64'), executionId: 'system-connector-.casesabc', source: 'SAVED_OBJECT', relatedSavedObjects: [ @@ -1646,10 +1655,10 @@ describe('bulkExecute()', () => { actionTypeRegistry: mockedActionTypeRegistry, inMemoryConnectors: [ { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', config: {}, - id: 'system-connector-.cases', - name: 'System action: .cases', + id: 'system-connector-test.system-action', + name: 'System action: test.system-action', secrets: {}, isPreconfigured: false, isDeprecated: false, @@ -1664,7 +1673,7 @@ describe('bulkExecute()', () => { id: '123', type: 'action', attributes: { - actionTypeId: '.cases', + actionTypeId: 'test.system-action', }, references: [], },