From c2825e2d749df79522305df98f0cd90ae2f2b5e3 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Fri, 12 Apr 2024 13:31:27 +0300 Subject: [PATCH 01/13] Remove unused translations --- .../components/system_actions/cases/translations.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/x-pack/plugins/cases/public/components/system_actions/cases/translations.ts b/x-pack/plugins/cases/public/components/system_actions/cases/translations.ts index 012c5c6fe681c..2d670a2ccb3c8 100644 --- a/x-pack/plugins/cases/public/components/system_actions/cases/translations.ts +++ b/x-pack/plugins/cases/public/components/system_actions/cases/translations.ts @@ -48,18 +48,6 @@ export const DAYS = (timeValue: string) => values: { timeValue }, }); -export const YEARS = (timeValue: string) => - i18n.translate('xpack.cases.systemActions.casesConnector.yearsLabel', { - defaultMessage: '{timeValue, plural, one {year} other {years}}', - values: { timeValue }, - }); - -export const MONTHS = (timeValue: string) => - i18n.translate('xpack.cases.systemActions.casesConnector.monthsLabel', { - defaultMessage: '{timeValue, plural, one {month} other {months}}', - values: { timeValue }, - }); - export const WEEKS = (timeValue: string) => i18n.translate('xpack.cases.systemActions.casesConnector.weeksLabel', { defaultMessage: '{timeValue, plural, one {week} other {weeks}}', From affa94fa260195758819457fa52825aa2b06b1cf Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Fri, 12 Apr 2024 13:46:40 +0300 Subject: [PATCH 02/13] Add the key as tag to cases --- .../cases/cases_connector_executor.test.ts | 23 +++++++++++++++++++ .../cases/cases_connector_executor.ts | 8 +++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts index e09cf40487dc6..d25700dc6d45c 100644 --- a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts +++ b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts @@ -253,7 +253,9 @@ describe('CasesConnectorExecutor', () => { tags: [ 'auto-generated', 'rule:rule-test-id', + 'host.name', 'host.name:A', + 'dest.ip', 'dest.ip:0.0.0.1', ...rule.tags, ], @@ -277,7 +279,9 @@ describe('CasesConnectorExecutor', () => { tags: [ 'auto-generated', 'rule:rule-test-id', + 'host.name', 'host.name:B', + 'dest.ip', 'dest.ip:0.0.0.1', ...rule.tags, ], @@ -301,7 +305,9 @@ describe('CasesConnectorExecutor', () => { tags: [ 'auto-generated', 'rule:rule-test-id', + 'host.name', 'host.name:B', + 'dest.ip', 'dest.ip:0.0.0.3', ...rule.tags, ], @@ -552,7 +558,9 @@ describe('CasesConnectorExecutor', () => { tags: [ 'auto-generated', 'rule:rule-test-id', + 'host.name', 'host.name:B', + 'dest.ip', 'dest.ip:0.0.0.3', ...rule.tags, ], @@ -706,7 +714,9 @@ describe('CasesConnectorExecutor', () => { expect(tags).toEqual([ 'auto-generated', 'rule:rule-test-id', + 'host.name', 'host.name:A', + 'dest.ip', 'dest.ip:0.0.0.1', 'a'.repeat(MAX_LENGTH_PER_TAG), ]); @@ -736,14 +746,18 @@ describe('CasesConnectorExecutor', () => { const systemTags = [ 'auto-generated', 'rule:rule-test-id', + 'host.name', 'host.name:A', + 'dest.ip', 'dest.ip:0.0.0.1', ]; expect(tags).toEqual([ 'auto-generated', 'rule:rule-test-id', + 'host.name', 'host.name:A', + 'dest.ip', 'dest.ip:0.0.0.1', ...Array(MAX_TAGS_PER_CASE - systemTags.length).fill('foo'), ]); @@ -783,8 +797,11 @@ describe('CasesConnectorExecutor', () => { expect(tags).toEqual([ 'auto-generated', 'rule:rule-test-id', + 'foo', 'foo:["bar",1,true,{}]', + 'bar.foo', 'bar.foo:test', + 'baz', 'baz:my value', 'rule', 'test', @@ -852,7 +869,9 @@ describe('CasesConnectorExecutor', () => { tags: [ 'auto-generated', 'rule:rule-test-id', + 'host.name', 'host.name:A', + 'dest.ip', 'dest.ip:0.0.0.1', ...rule.tags, ], @@ -960,7 +979,9 @@ describe('CasesConnectorExecutor', () => { tags: [ 'auto-generated', 'rule:rule-test-id', + 'host.name', 'host.name:B', + 'dest.ip', 'dest.ip:0.0.0.3', ...rule.tags, ], @@ -1009,7 +1030,9 @@ describe('CasesConnectorExecutor', () => { tags: [ 'auto-generated', 'rule:rule-test-id', + 'host.name', 'host.name:A', + 'dest.ip', 'dest.ip:0.0.0.1', ...rule.tags, ], diff --git a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts index a5f07a9b65fc7..3bf67c0424240 100644 --- a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts +++ b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts @@ -789,11 +789,11 @@ export class CasesConnectorExecutor { .map((tag) => tag.slice(0, MAX_LENGTH_PER_TAG)); } - private getGroupingAsTags(grouping: GroupedAlerts['grouping']) { + private getGroupingAsTags(grouping: GroupedAlerts['grouping']): string[] { const flattenGrouping = getFlattenedObject(grouping); - return Object.entries(flattenGrouping).map( - ([key, value]) => `${key}:${convertValueToString(value)}` - ); + return Object.entries(flattenGrouping) + .map(([key, value]) => [key, `${key}:${convertValueToString(value)}`]) + .flat(); } private async handleClosedCases( From 94989f85294ed7dcb910cd438f283ac5a6429ab0 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Sat, 13 Apr 2024 16:42:00 +0300 Subject: [PATCH 03/13] Improve the tags, title, and the description --- .../cases/cases_connector_executor.test.ts | 485 ++++++++++-------- .../cases/cases_connector_executor.ts | 61 ++- 2 files changed, 294 insertions(+), 252 deletions(-) diff --git a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts index d25700dc6d45c..3f47c9e3f14a0 100644 --- a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts +++ b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts @@ -239,88 +239,94 @@ describe('CasesConnectorExecutor', () => { }); expect(casesClientMock.cases.bulkCreate).toHaveBeenCalledTimes(1); - expect(casesClientMock.cases.bulkCreate).toHaveBeenCalledWith({ - cases: [ - { - id: 'mock-id-1', - title: 'Test rule (Auto-created)', - description: - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping: `host.name` equals `A` and `dest.ip` equals `0.0.0.1`', - owner: 'cases', - settings: { - syncAlerts: false, - }, - tags: [ - 'auto-generated', - 'rule:rule-test-id', - 'host.name', - 'host.name:A', - 'dest.ip', - 'dest.ip:0.0.0.1', - ...rule.tags, - ], - connector: { - fields: null, - id: 'none', - name: 'none', - type: '.none', - }, - customFields: [], - }, - { - id: 'mock-id-2', - title: 'Test rule (Auto-created)', - description: - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping: `host.name` equals `B` and `dest.ip` equals `0.0.0.1`', - owner: 'cases', - settings: { - syncAlerts: false, - }, - tags: [ - 'auto-generated', - 'rule:rule-test-id', - 'host.name', - 'host.name:B', - 'dest.ip', - 'dest.ip:0.0.0.1', - ...rule.tags, - ], - connector: { - fields: null, - id: 'none', - name: 'none', - type: '.none', - }, - customFields: [], - }, - { - id: 'mock-id-3', - title: 'Test rule (Auto-created)', - description: - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping: `host.name` equals `B` and `dest.ip` equals `0.0.0.3`', - owner: 'cases', - settings: { - syncAlerts: false, - }, - tags: [ - 'auto-generated', - 'rule:rule-test-id', - 'host.name', - 'host.name:B', - 'dest.ip', - 'dest.ip:0.0.0.3', - ...rule.tags, - ], - connector: { - fields: null, - id: 'none', - name: 'none', - type: '.none', + expect(casesClientMock.cases.bulkCreate.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "cases": Array [ + Object { + "connector": Object { + "fields": null, + "id": "none", + "name": "none", + "type": ".none", + }, + "customFields": Array [], + "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", + "id": "mock-id-1", + "owner": "cases", + "settings": Object { + "syncAlerts": false, + }, + "tags": Array [ + "auto-generated", + "rule:rule-test-id", + "host.name", + "host.name:A", + "dest.ip", + "dest.ip:0.0.0.1", + "rule", + "test", + ], + "title": "Test rule - Grouping by A & 0.0.0.1 (Auto-created)", + }, + Object { + "connector": Object { + "fields": null, + "id": "none", + "name": "none", + "type": ".none", + }, + "customFields": Array [], + "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.1\`.", + "id": "mock-id-2", + "owner": "cases", + "settings": Object { + "syncAlerts": false, + }, + "tags": Array [ + "auto-generated", + "rule:rule-test-id", + "host.name", + "host.name:B", + "dest.ip", + "dest.ip:0.0.0.1", + "rule", + "test", + ], + "title": "Test rule - Grouping by B & 0.0.0.1 (Auto-created)", + }, + Object { + "connector": Object { + "fields": null, + "id": "none", + "name": "none", + "type": ".none", + }, + "customFields": Array [], + "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", + "id": "mock-id-3", + "owner": "cases", + "settings": Object { + "syncAlerts": false, + }, + "tags": Array [ + "auto-generated", + "rule:rule-test-id", + "host.name", + "host.name:B", + "dest.ip", + "dest.ip:0.0.0.3", + "rule", + "test", + ], + "title": "Test rule - Grouping by B & 0.0.0.3 (Auto-created)", + }, + ], }, - customFields: [], - }, - ], - }); + ], + ] + `); expectCasesToHaveTheCorrectAlertsAttachedWithGrouping(casesClientMock); }); @@ -544,36 +550,38 @@ describe('CasesConnectorExecutor', () => { await connectorExecutor.execute(params); - expect(casesClientMock.cases.bulkCreate).toHaveBeenCalledWith({ - cases: [ - { - id: 'mock-id-3', - title: 'Test rule (Auto-created)', - description: - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping: `host.name` equals `B` and `dest.ip` equals `0.0.0.3`', - owner: 'cases', - settings: { - syncAlerts: false, - }, - tags: [ - 'auto-generated', - 'rule:rule-test-id', - 'host.name', - 'host.name:B', - 'dest.ip', - 'dest.ip:0.0.0.3', - ...rule.tags, - ], - connector: { - fields: null, - id: 'none', - name: 'none', - type: '.none', + expect(casesClientMock.cases.bulkCreate.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "cases": Array [ + Object { + "connector": Object { + "fields": null, + "id": "none", + "name": "none", + "type": ".none", + }, + "customFields": Array [], + "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", + "id": "mock-id-3", + "owner": "cases", + "settings": Object { + "syncAlerts": false, + }, + "tags": Array [ + "auto-generated", + "rule:rule-test-id", + "host.name", + "host.name:B", + "dest.ip", + "dest.ip:0.0.0.3", + "rule", + "test", + ], + "title": "Test rule - Grouping by B & 0.0.0.3 (Auto-created)", }, - customFields: [], - }, - ], - }); + ], + } + `); }); it('does not add the rule URL to the description if the ruleUrl is null', async () => { @@ -599,8 +607,8 @@ describe('CasesConnectorExecutor', () => { const description = casesClientMock.cases.bulkCreate.mock.calls[0][0].cases[0].description; - expect(description).toBe( - 'This case is auto-created by Test rule. \n\n Grouping: `host.name` equals `A` and `dest.ip` equals `0.0.0.1`' + expect(description).toMatchInlineSnapshot( + `"This case was created by the Case action in Test rule. The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`."` ); }); @@ -636,8 +644,8 @@ describe('CasesConnectorExecutor', () => { const description = casesClientMock.cases.bulkCreate.mock.calls[0][0].cases[0].description; - expect(description).toBe( - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping: `foo` equals `["bar",1,true,{}]` and `bar.foo` equals `test` and `baz` equals `my value`' + expect(description).toMatchInlineSnapshot( + `"This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`foo: [\\"bar\\",1,true,{}]\` and \`bar.foo: test\` and \`baz: my value\`."` ); }); @@ -659,7 +667,7 @@ describe('CasesConnectorExecutor', () => { await connectorExecutor.execute({ ...params, groupingBy: [] }); const title = casesClientMock.cases.bulkCreate.mock.calls[0][0].cases[0].title; - expect(title).toBe('Test rule (2) (Auto-created)'); + expect(title).toMatchInlineSnapshot(`"Test rule (2) (Auto-created)"`); }); it(`trims the title correctly if the rule title including the suffix is bigger than ${MAX_TITLE_LENGTH}`, async () => { @@ -685,7 +693,7 @@ describe('CasesConnectorExecutor', () => { const title = casesClientMock.cases.bulkCreate.mock.calls[0][0].cases[0].title; - expect(title.length).toBe(MAX_TITLE_LENGTH); + expect(title.length).toBeLessThanOrEqual(MAX_TITLE_LENGTH); expect(title.includes('(2) (Auto-created)')).toBe(true); }); @@ -855,36 +863,38 @@ describe('CasesConnectorExecutor', () => { { payload: { counter: 2 }, recordId: 'so-oracle-record-0', version: 'so-version-0' }, ]); - expect(casesClientMock.cases.bulkCreate).toHaveBeenCalledWith({ - cases: [ - { - id: 'mock-id-4', - title: 'Test rule (Auto-created)', - description: - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping: `host.name` equals `A` and `dest.ip` equals `0.0.0.1`', - owner: 'cases', - settings: { - syncAlerts: false, - }, - tags: [ - 'auto-generated', - 'rule:rule-test-id', - 'host.name', - 'host.name:A', - 'dest.ip', - 'dest.ip:0.0.0.1', - ...rule.tags, - ], - connector: { - fields: null, - id: 'none', - name: 'none', - type: '.none', + expect(casesClientMock.cases.bulkCreate.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "cases": Array [ + Object { + "connector": Object { + "fields": null, + "id": "none", + "name": "none", + "type": ".none", + }, + "customFields": Array [], + "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", + "id": "mock-id-4", + "owner": "cases", + "settings": Object { + "syncAlerts": false, + }, + "tags": Array [ + "auto-generated", + "rule:rule-test-id", + "host.name", + "host.name:A", + "dest.ip", + "dest.ip:0.0.0.1", + "rule", + "test", + ], + "title": "Test rule - Grouping by A & 0.0.0.1 (Auto-created)", }, - customFields: [], - }, - ], - }); + ], + } + `); }); describe('Custom Fields', () => { @@ -924,28 +934,6 @@ describe('CasesConnectorExecutor', () => { ], }, ]; - const expectedCustomFieldValues = [ - { - key: 'first_key', - type: CustomFieldTypes.TEXT as const, - value: 'default value', - }, - { - key: 'second_key', - type: CustomFieldTypes.TOGGLE as const, - value: true, - }, - { - key: 'third_key', - type: CustomFieldTypes.TEXT as const, - value: 'N/A', - }, - { - key: 'fourth_key', - type: CustomFieldTypes.TOGGLE as const, - value: false, - }, - ]; it('creates non existing cases with required custom fields correctly', async () => { casesClientMock.configure.get = jest.fn().mockResolvedValue(mockConfiguration); @@ -965,36 +953,59 @@ describe('CasesConnectorExecutor', () => { await connectorExecutor.execute(params); - expect(casesClientMock.cases.bulkCreate).toHaveBeenCalledWith({ - cases: [ - { - id: 'mock-id-3', - title: 'Test rule (Auto-created)', - description: - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping: `host.name` equals `B` and `dest.ip` equals `0.0.0.3`', - owner: mockOwner, - settings: { - syncAlerts: false, - }, - tags: [ - 'auto-generated', - 'rule:rule-test-id', - 'host.name', - 'host.name:B', - 'dest.ip', - 'dest.ip:0.0.0.3', - ...rule.tags, - ], - connector: { - fields: null, - id: 'none', - name: 'none', - type: '.none', + expect(casesClientMock.cases.bulkCreate.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "cases": Array [ + Object { + "connector": Object { + "fields": null, + "id": "none", + "name": "none", + "type": ".none", + }, + "customFields": Array [ + Object { + "key": "first_key", + "type": "text", + "value": "default value", + }, + Object { + "key": "second_key", + "type": "toggle", + "value": true, + }, + Object { + "key": "third_key", + "type": "text", + "value": "N/A", + }, + Object { + "key": "fourth_key", + "type": "toggle", + "value": false, + }, + ], + "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", + "id": "mock-id-3", + "owner": "cases", + "settings": Object { + "syncAlerts": false, + }, + "tags": Array [ + "auto-generated", + "rule:rule-test-id", + "host.name", + "host.name:B", + "dest.ip", + "dest.ip:0.0.0.3", + "rule", + "test", + ], + "title": "Test rule - Grouping by B & 0.0.0.3 (Auto-created)", }, - customFields: expectedCustomFieldValues, - }, - ], - }); + ], + } + `); }); it('creates new cases with required custom fields if reopenClosedCases=false and there are closed cases', async () => { @@ -1016,37 +1027,59 @@ describe('CasesConnectorExecutor', () => { { payload: { counter: 2 }, recordId: 'so-oracle-record-0', version: 'so-version-0' }, ]); - expect(casesClientMock.cases.bulkCreate).toHaveBeenCalledWith({ - cases: [ - { - id: 'mock-id-4', - title: 'Test rule (Auto-created)', - description: - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping: `host.name` equals `A` and `dest.ip` equals `0.0.0.1`', - owner: mockOwner, - settings: { - syncAlerts: false, - }, - tags: [ - 'auto-generated', - 'rule:rule-test-id', - 'host.name', - 'host.name:A', - 'dest.ip', - 'dest.ip:0.0.0.1', - ...rule.tags, - ], - - connector: { - fields: null, - id: 'none', - name: 'none', - type: '.none', + expect(casesClientMock.cases.bulkCreate.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "cases": Array [ + Object { + "connector": Object { + "fields": null, + "id": "none", + "name": "none", + "type": ".none", + }, + "customFields": Array [ + Object { + "key": "first_key", + "type": "text", + "value": "default value", + }, + Object { + "key": "second_key", + "type": "toggle", + "value": true, + }, + Object { + "key": "third_key", + "type": "text", + "value": "N/A", + }, + Object { + "key": "fourth_key", + "type": "toggle", + "value": false, + }, + ], + "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", + "id": "mock-id-4", + "owner": "cases", + "settings": Object { + "syncAlerts": false, + }, + "tags": Array [ + "auto-generated", + "rule:rule-test-id", + "host.name", + "host.name:A", + "dest.ip", + "dest.ip:0.0.0.1", + "rule", + "test", + ], + "title": "Test rule - Grouping by A & 0.0.0.1 (Auto-created)", }, - customFields: expectedCustomFieldValues, - }, - ], - }); + ], + } + `); }); }); }); diff --git a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts index 3bf67c0424240..159232685fcc0 100644 --- a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts +++ b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts @@ -717,13 +717,7 @@ export class CasesConnectorExecutor { customFieldsConfigurations?: CustomFieldsConfiguration ): Omit & { id: string } { const { grouping, caseId, oracleRecord } = groupingData; - - const ruleName = params.rule.ruleUrl - ? `[${params.rule.name}](${params.rule.ruleUrl})` - : params.rule.name; - - const groupingDescription = this.getGroupingDescription(grouping); - const description = `This case is auto-created by ${ruleName}. \n\n Grouping: ${groupingDescription}`; + const flattenGrouping = getFlattenedObject(grouping); const requiredCustomFields = buildRequiredCustomFieldsForRequest(customFieldsConfigurations); this.logger.debug( @@ -739,9 +733,9 @@ export class CasesConnectorExecutor { return { id: caseId, - description, - tags: this.getCaseTags(params, grouping), - title: this.getCasesTitle(params.rule.name, oracleRecord.counter), + description: this.getCaseDescription(params, flattenGrouping), + tags: this.getCaseTags(params, flattenGrouping), + title: this.getCasesTitle(params, flattenGrouping, oracleRecord.counter), connector: { id: 'none', name: 'none', type: ConnectorTypes.none, fields: null }, /** * TODO: Turn on for Security solution @@ -752,28 +746,44 @@ export class CasesConnectorExecutor { }; } - private getCasesTitle(ruleName: string, oracleCounter: number) { - const suffix = - oracleCounter === INITIAL_ORACLE_RECORD_COUNTER - ? '(Auto-created)' - : `(${oracleCounter}) (Auto-created)`; + private getCasesTitle( + params: CasesConnectorRunParams, + grouping: GroupedAlerts['grouping'], + oracleCounter: number + ) { + const groupingDescription = Object.entries(grouping) + .map(([_, value]) => { + return convertValueToString(value); + }) + .join(' & '); + + const suffix = `${ + groupingDescription.length > 0 ? ` - Grouping by ${groupingDescription}` : '' + }${oracleCounter > INITIAL_ORACLE_RECORD_COUNTER ? ` (${oracleCounter})` : ''} (Auto-created)`; - const ruleNameTrimmed = ruleName.slice(0, MAX_TITLE_LENGTH - suffix.length - 1); + const ruleNameTrimmed = params.rule.name.slice(0, MAX_TITLE_LENGTH - suffix.length - 1); - return `${ruleNameTrimmed} ${suffix}`; + return `${ruleNameTrimmed}${suffix}`; } - private getGroupingDescription(grouping: GroupedAlerts['grouping']) { - const flattenGrouping = getFlattenedObject(grouping); + private getCaseDescription(params: CasesConnectorRunParams, grouping: GroupedAlerts['grouping']) { + const ruleName = params.rule.ruleUrl + ? `[${params.rule.name}](${params.rule.ruleUrl})` + : params.rule.name; - return Object.entries(flattenGrouping) - .map(([key, value]) => { - const keyAsCodeBlock = `\`${key}\``; - const valueAsCodeBlock = `\`${convertValueToString(value)}\``; + const description = `This case was created by the Case action in ${ruleName}.`; - return `${keyAsCodeBlock} equals ${valueAsCodeBlock}`; + const groupingDescription = Object.entries(grouping) + .map(([key, value]) => { + return `\`${key}: ${convertValueToString(value)}\``; }) .join(' and '); + + if (groupingDescription.length > 0) { + return `${description} The assigned alerts are grouped by ${groupingDescription}.`; + } + + return `${description}`; } private getCaseTags(params: CasesConnectorRunParams, grouping: GroupedAlerts['grouping']) { @@ -790,8 +800,7 @@ export class CasesConnectorExecutor { } private getGroupingAsTags(grouping: GroupedAlerts['grouping']): string[] { - const flattenGrouping = getFlattenedObject(grouping); - return Object.entries(flattenGrouping) + return Object.entries(grouping) .map(([key, value]) => [key, `${key}:${convertValueToString(value)}`]) .flat(); } From b7fece71ee5a102b51d7f678fd5f86e8dad3d15e Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Sat, 13 Apr 2024 16:50:37 +0300 Subject: [PATCH 04/13] Pass the producer to the connector adapter --- .../rule/methods/bulk_edit/bulk_edit_rules.ts | 2 +- .../application/rule/methods/create/create_rule.ts | 2 +- .../get_system_action_kibana_privileges.ts | 7 +++++-- .../alerting/server/connector_adapters/types.ts | 6 ++++-- .../server/lib/validate_authorize_system_actions.ts | 4 ++-- .../alerting/server/rules_client/methods/update.ts | 2 +- .../server/task_runner/execution_handler.test.ts | 1 + .../alerting/server/task_runner/execution_handler.ts | 11 ++++++++++- 8 files changed, 25 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts index e31b1ffa8c1dc..6cb77e6e32a2a 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts @@ -687,7 +687,7 @@ async function getUpdatedAttributesFromOperations({ actionsAuthorization: context.actionsAuthorization, connectorAdapterRegistry: context.connectorAdapterRegistry, systemActions: genSystemActions, - rule: { consumer: updatedRule.consumer }, + rule: { consumer: updatedRule.consumer, producer: ruleType.producer }, }); try { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts index e86744b421bb8..5b77fcbbb6a91 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts @@ -155,7 +155,7 @@ export async function createRule( actionsAuthorization: context.actionsAuthorization, connectorAdapterRegistry: context.connectorAdapterRegistry, systemActions: data.systemActions, - rule: { consumer: data.consumer }, + rule: { consumer: data.consumer, producer: ruleType.producer }, }) ); diff --git a/x-pack/plugins/alerting/server/connector_adapters/get_system_action_kibana_privileges.ts b/x-pack/plugins/alerting/server/connector_adapters/get_system_action_kibana_privileges.ts index 2ffaaf5ead318..0dd06e7776ba7 100644 --- a/x-pack/plugins/alerting/server/connector_adapters/get_system_action_kibana_privileges.ts +++ b/x-pack/plugins/alerting/server/connector_adapters/get_system_action_kibana_privileges.ts @@ -10,7 +10,7 @@ import { ConnectorAdapterRegistry } from './connector_adapter_registry'; interface Args { connectorAdapterRegistry: ConnectorAdapterRegistry; - rule: { consumer: string }; + rule: { consumer: string; producer: string }; systemActions?: RuleSystemAction[]; } @@ -22,7 +22,10 @@ export const getSystemActionKibanaPrivileges = ({ const kibanaPrivileges = systemActions .filter((action) => connectorAdapterRegistry.has(action.actionTypeId)) .map((action) => connectorAdapterRegistry.get(action.actionTypeId)) - .map((adapter) => adapter.getKibanaPrivileges?.({ consumer: rule.consumer }) ?? []) + .map( + (adapter) => + adapter.getKibanaPrivileges?.({ consumer: rule.consumer, producer: rule.producer }) ?? [] + ) .flat(); return Array.from(new Set(kibanaPrivileges)); diff --git a/x-pack/plugins/alerting/server/connector_adapters/types.ts b/x-pack/plugins/alerting/server/connector_adapters/types.ts index e33fe1613be68..e189c53cfecfe 100644 --- a/x-pack/plugins/alerting/server/connector_adapters/types.ts +++ b/x-pack/plugins/alerting/server/connector_adapters/types.ts @@ -9,7 +9,9 @@ import { ObjectType } from '@kbn/config-schema'; import type { RuleTypeParams, SanitizedRule } from '../../common'; import { CombinedSummarizedAlerts } from '../types'; -type Rule = Pick, 'id' | 'name' | 'tags' | 'consumer'>; +type Rule = Pick, 'id' | 'name' | 'tags' | 'consumer'> & { + producer: string; +}; export interface ConnectorAdapterParams { [x: string]: unknown; @@ -38,5 +40,5 @@ export interface ConnectorAdapter< */ ruleActionParamsSchema: ObjectType; buildActionParams: (args: BuildActionParamsArgs) => ConnectorParams; - getKibanaPrivileges?: ({ consumer }: { consumer: string }) => string[]; + getKibanaPrivileges?: (args: { consumer: string; producer: string }) => string[]; } diff --git a/x-pack/plugins/alerting/server/lib/validate_authorize_system_actions.ts b/x-pack/plugins/alerting/server/lib/validate_authorize_system_actions.ts index 22ab3f32d3d7a..3c88797581ef1 100644 --- a/x-pack/plugins/alerting/server/lib/validate_authorize_system_actions.ts +++ b/x-pack/plugins/alerting/server/lib/validate_authorize_system_actions.ts @@ -17,7 +17,7 @@ interface Params { actionsAuthorization: ActionsAuthorization; connectorAdapterRegistry: ConnectorAdapterRegistry; systemActions: Array; - rule: { consumer: string }; + rule: { consumer: string; producer: string }; } export const validateAndAuthorizeSystemActions = async ({ @@ -73,7 +73,7 @@ export const validateAndAuthorizeSystemActions = async ({ const additionalPrivileges = getSystemActionKibanaPrivileges({ connectorAdapterRegistry, systemActions: systemActionsWithActionTypeId, - rule: { consumer: rule.consumer }, + rule: { consumer: rule.consumer, producer: rule.producer }, }); await actionsAuthorization.ensureAuthorized({ operation: 'execute', additionalPrivileges }); diff --git a/x-pack/plugins/alerting/server/rules_client/methods/update.ts b/x-pack/plugins/alerting/server/rules_client/methods/update.ts index 886f112ba2984..68b62d7e098ff 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/update.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/update.ts @@ -250,7 +250,7 @@ async function updateAlert( actionsAuthorization: context.actionsAuthorization, connectorAdapterRegistry: context.connectorAdapterRegistry, systemActions: data.systemActions, - rule: { consumer: currentRule.attributes.consumer }, + rule: { consumer: currentRule.attributes.consumer, producer: ruleType.producer }, }); // Throw error if schedule interval is less than the minimum and we are enforcing it diff --git a/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts index 47022933e93a1..b22d7b70a9d49 100644 --- a/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts @@ -2474,6 +2474,7 @@ describe('Execution Handler', () => { name: rule.name, tags: rule.tags, consumer: 'test-consumer', + producer: 'alerts', }, ruleUrl: 'https://example.com/s/test1/app/management/insightsAndAlerting/triggersActions/rule/1', diff --git a/x-pack/plugins/alerting/server/task_runner/execution_handler.ts b/x-pack/plugins/alerting/server/task_runner/execution_handler.ts index e268162b88f1b..72dd7a06bb5fd 100644 --- a/x-pack/plugins/alerting/server/task_runner/execution_handler.ts +++ b/x-pack/plugins/alerting/server/task_runner/execution_handler.ts @@ -88,6 +88,7 @@ interface RunSystemActionArgs { connectorAdapter: ConnectorAdapter; summarizedAlerts: CombinedSummarizedAlerts; rule: SanitizedRule; + ruleProducer: string; spaceId: string; bulkActions: EnqueueExecutionOptions[]; } @@ -318,6 +319,7 @@ export class ExecutionHandler< connectorAdapter, summarizedAlerts, rule: this.rule, + ruleProducer: this.ruleType.producer, spaceId, bulkActions, }); @@ -453,13 +455,20 @@ export class ExecutionHandler< connectorAdapter, summarizedAlerts, rule, + ruleProducer, bulkActions, }: RunSystemActionArgs): Promise { const ruleUrl = this.buildRuleUrl(spaceId); const connectorAdapterActionParams = connectorAdapter.buildActionParams({ alerts: summarizedAlerts, - rule: { id: rule.id, tags: rule.tags, name: rule.name, consumer: rule.consumer }, + rule: { + id: rule.id, + tags: rule.tags, + name: rule.name, + consumer: rule.consumer, + producer: ruleProducer, + }, ruleUrl: ruleUrl?.absoluteUrl, spaceId, params: action.params, From 2937b4a12d407f2b8f7c4f5faa93db6b1d7383a0 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Sat, 13 Apr 2024 17:00:11 +0300 Subject: [PATCH 05/13] Use producer to get the if the consumer is not found --- .../server/connectors/cases/index.test.ts | 28 ++++++++++++++++++- .../cases/server/connectors/cases/index.ts | 10 +++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/cases/server/connectors/cases/index.test.ts b/x-pack/plugins/cases/server/connectors/cases/index.test.ts index ee559b335ef20..bd5e2ea71098f 100644 --- a/x-pack/plugins/cases/server/connectors/cases/index.test.ts +++ b/x-pack/plugins/cases/server/connectors/cases/index.test.ts @@ -65,6 +65,7 @@ describe('getCasesConnectorType', () => { name: 'my rule name', tags: ['my-tag'], consumer: 'test-consumer', + producer: 'test-producer', }; const getParams = (overrides = {}) => ({ @@ -272,7 +273,12 @@ describe('getCasesConnectorType', () => { it('constructs the correct privileges from the consumer', () => { const adapter = getCasesConnectorAdapter(); - expect(adapter.getKibanaPrivileges?.({ consumer: AlertConsumers.SIEM })).toEqual([ + expect( + adapter.getKibanaPrivileges?.({ + consumer: AlertConsumers.SIEM, + producer: AlertConsumers.SIEM, + }) + ).toEqual([ 'cases:securitySolution/createCase', 'cases:securitySolution/updateCase', 'cases:securitySolution/deleteCase', @@ -283,6 +289,26 @@ describe('getCasesConnectorType', () => { 'cases:securitySolution/findConfigurations', ]); }); + + it('constructs the correct privileges from the producer if the consumer is not found', () => { + const adapter = getCasesConnectorAdapter(); + + expect( + adapter.getKibanaPrivileges?.({ + consumer: 'alerting', + producer: AlertConsumers.LOGS, + }) + ).toEqual([ + 'cases:observability/createCase', + 'cases:observability/updateCase', + 'cases:observability/deleteCase', + 'cases:observability/pushCase', + 'cases:observability/createComment', + 'cases:observability/updateComment', + 'cases:observability/deleteComment', + 'cases:observability/findConfigurations', + ]); + }); }); }); }); diff --git a/x-pack/plugins/cases/server/connectors/cases/index.ts b/x-pack/plugins/cases/server/connectors/cases/index.ts index bec6fdcb97b69..6e9e6601cecc7 100644 --- a/x-pack/plugins/cases/server/connectors/cases/index.ts +++ b/x-pack/plugins/cases/server/connectors/cases/index.ts @@ -80,7 +80,7 @@ export const getCasesConnectorAdapter = (): ConnectorAdapter< buildActionParams: ({ alerts, rule, params, spaceId, ruleUrl }) => { const caseAlerts = [...alerts.new.data, ...alerts.ongoing.data]; - const owner = getOwnerFromRuleConsumer(rule.consumer); + const owner = getOwnerFromRuleConsumerProducer(rule.consumer, rule.producer); const subActionParams = { alerts: caseAlerts, @@ -94,17 +94,17 @@ export const getCasesConnectorAdapter = (): ConnectorAdapter< return { subAction: 'run', subActionParams }; }, - getKibanaPrivileges: ({ consumer }) => { - const owner = getOwnerFromRuleConsumer(consumer); + getKibanaPrivileges: ({ consumer, producer }) => { + const owner = getOwnerFromRuleConsumerProducer(consumer, producer); return constructRequiredKibanaPrivileges(owner); }, }; }; -const getOwnerFromRuleConsumer = (consumer: string): Owner => { +const getOwnerFromRuleConsumerProducer = (consumer: string, producer: string): Owner => { for (const value of Object.values(OWNER_INFO)) { const foundedConsumer = value.validRuleConsumers?.find( - (validConsumer) => validConsumer === consumer + (validConsumer) => validConsumer === consumer || validConsumer === producer ); if (foundedConsumer) { From 78ce0eaeb3fedde875fa073cd032aecaebd3c816 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Mon, 15 Apr 2024 10:13:14 +0300 Subject: [PATCH 06/13] Previous PR feedback --- x-pack/plugins/cases/server/connectors/cases/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/server/connectors/cases/README.md b/x-pack/plugins/cases/server/connectors/cases/README.md index de04640dcf181..bc5cbf3415440 100644 --- a/x-pack/plugins/cases/server/connectors/cases/README.md +++ b/x-pack/plugins/cases/server/connectors/cases/README.md @@ -78,7 +78,7 @@ top --> bottom ## Grouping -The case action accepts an array of alerts provided by the connector adapter. Duplicate alerts will not be attached to the same case. The case action groups the alerts by the grouping field configured by the user. For example, if the grouping field is `host.name` the case action will group the alerts by the values of the `host.name` field. Users may define more than one grouping field. In this case, the grouping will be done by multiple fields. The grouping is performed in memory by the case action as the number of alerts is expected to be low on average and they are already loaded in memory by the alerting framework. +The case action accepts an array of alerts provided by the connector adapter. Duplicate alerts will not be attached to the same case. The case action groups the alerts by the grouping field configured by the user. For example, if the grouping field is `host.name` the case action will group the alerts by the values of the `host.name` field. In this case, the grouping will be done by multiple fields. The grouping is performed in memory by the case action as the number of alerts is expected to be low on average and they are already loaded in memory by the alerting framework. ```mermaid flowchart LR From 5700eea5b233ae635086771d05a047ab4f515577 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Mon, 15 Apr 2024 11:36:29 +0300 Subject: [PATCH 07/13] Fix integration tests --- .../trial/connectors/cases/cases_connector.ts | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/connectors/cases/cases_connector.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/connectors/cases/cases_connector.ts index 1e38e803ca18e..15b1b344d8338 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/connectors/cases/cases_connector.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/connectors/cases/cases_connector.ts @@ -323,7 +323,7 @@ export default ({ getService }: FtrProviderContext): void => { }, customFields: [], description: - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping:', + 'This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id).', duration: null, external_service: null, id: 'ee06877e50151293e75cd6c5bd81812c15c25be55ed970f91c6f7dc40e1eafa6', @@ -693,7 +693,7 @@ export default ({ getService }: FtrProviderContext): void => { }, customFields: [], description: - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping: `host.name` equals `A`', + 'This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by `host.name: A`.', duration: null, external_service: null, id: firstCaseId, @@ -703,8 +703,15 @@ export default ({ getService }: FtrProviderContext): void => { }, severity: 'low', status: 'open', - tags: ['auto-generated', 'rule:rule-test-id', 'host.name:A', 'rule', 'test'], - title: 'Test rule (Auto-created)', + tags: [ + 'auto-generated', + 'rule:rule-test-id', + 'host.name', + 'host.name:A', + 'rule', + 'test', + ], + title: 'Test rule - Grouping by A (Auto-created)', totalAlerts: 3, totalComment: 0, updated_by: { @@ -733,7 +740,7 @@ export default ({ getService }: FtrProviderContext): void => { }, customFields: [], description: - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping: `host.name` equals `B`', + 'This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by `host.name: B`.', duration: null, external_service: null, id: secondCaseId, @@ -743,8 +750,15 @@ export default ({ getService }: FtrProviderContext): void => { }, severity: 'low', status: 'open', - tags: ['auto-generated', 'rule:rule-test-id', 'host.name:B', 'rule', 'test'], - title: 'Test rule (Auto-created)', + tags: [ + 'auto-generated', + 'rule:rule-test-id', + 'host.name', + 'host.name:B', + 'rule', + 'test', + ], + title: 'Test rule - Grouping by B (Auto-created)', totalAlerts: 2, totalComment: 0, updated_by: { @@ -981,10 +995,10 @@ export default ({ getService }: FtrProviderContext): void => { ); expect(firstCase.description).to.be( - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping: `host.name` equals `A`' + 'This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by `host.name: A`.' ); expect(secondCase.description).to.be( - 'This case is auto-created by [Test rule](https://example.com/rules/rule-test-id). \n\n Grouping: `host.name` equals `unknown`' + 'This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by `host.name: unknown`.' ); const firstCaseAttachments = await getAllComments({ From 9291a9599c2562032ca51ece7c036c4114c8e401 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Tue, 16 Apr 2024 12:31:35 +0300 Subject: [PATCH 08/13] Fix merge --- .../server/application/rule/methods/update/update_rule.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.ts index 93701c344bc0e..eef9026a14cd4 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/update/update_rule.ts @@ -176,7 +176,7 @@ async function updateWithOCC( actionsAuthorization: context.actionsAuthorization, connectorAdapterRegistry: context.connectorAdapterRegistry, systemActions: data.systemActions, - rule: { consumer: originalRuleSavedObject.attributes.consumer }, + rule: { consumer: originalRuleSavedObject.attributes.consumer, producer: ruleType.producer }, }); // Throw error if schedule interval is less than the minimum and we are enforcing it From c23f48fbbe23a1067e66081aa70089d0bb6e3fa3 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Tue, 16 Apr 2024 12:44:19 +0300 Subject: [PATCH 09/13] Add eclipses at the end of the trimmed rule name --- .../cases/cases_connector_executor.test.ts | 4 +++- .../connectors/cases/cases_connector_executor.ts | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts index 3f47c9e3f14a0..bd08cb077a908 100644 --- a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts +++ b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts @@ -694,7 +694,9 @@ describe('CasesConnectorExecutor', () => { const title = casesClientMock.cases.bulkCreate.mock.calls[0][0].cases[0].title; expect(title.length).toBeLessThanOrEqual(MAX_TITLE_LENGTH); - expect(title.includes('(2) (Auto-created)')).toBe(true); + expect(title).toMatchInlineSnapshot( + `"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa... (2) (Auto-created)"` + ); }); it(`trims tags that are bigger than ${MAX_LENGTH_PER_TAG} characters`, async () => { diff --git a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts index 159232685fcc0..12df76eabd8c8 100644 --- a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts +++ b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts @@ -751,6 +751,8 @@ export class CasesConnectorExecutor { grouping: GroupedAlerts['grouping'], oracleCounter: number ) { + const totalDots = 3; + const groupingDescription = Object.entries(grouping) .map(([_, value]) => { return convertValueToString(value); @@ -761,9 +763,17 @@ export class CasesConnectorExecutor { groupingDescription.length > 0 ? ` - Grouping by ${groupingDescription}` : '' }${oracleCounter > INITIAL_ORACLE_RECORD_COUNTER ? ` (${oracleCounter})` : ''} (Auto-created)`; - const ruleNameTrimmed = params.rule.name.slice(0, MAX_TITLE_LENGTH - suffix.length - 1); + const ruleNameTrimmed = params.rule.name.slice( + 0, + MAX_TITLE_LENGTH - suffix.length - totalDots - 1 + ); + + const ruleNameTrimmedWithDots = + params.rule.name.length > ruleNameTrimmed.length + ? `${ruleNameTrimmed}${'.'.repeat(totalDots)}` + : ruleNameTrimmed; - return `${ruleNameTrimmed}${suffix}`; + return `${ruleNameTrimmedWithDots}${suffix}`; } private getCaseDescription(params: CasesConnectorRunParams, grouping: GroupedAlerts['grouping']) { From 81667dd9972ee314f666acb87262fc74d9a4deef Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Tue, 16 Apr 2024 12:59:59 +0300 Subject: [PATCH 10/13] Translate the title and the description --- .../cases/cases_connector_executor.test.ts | 18 +++++----- .../cases/cases_connector_executor.ts | 16 ++++++--- .../server/connectors/cases/translations.ts | 36 +++++++++++++++++++ 3 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 x-pack/plugins/cases/server/connectors/cases/translations.ts diff --git a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts index bd08cb077a908..7e51410d248ec 100644 --- a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts +++ b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts @@ -252,7 +252,7 @@ describe('CasesConnectorExecutor', () => { "type": ".none", }, "customFields": Array [], - "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", + "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", "id": "mock-id-1", "owner": "cases", "settings": Object { @@ -278,7 +278,7 @@ describe('CasesConnectorExecutor', () => { "type": ".none", }, "customFields": Array [], - "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.1\`.", + "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.1\`.", "id": "mock-id-2", "owner": "cases", "settings": Object { @@ -304,7 +304,7 @@ describe('CasesConnectorExecutor', () => { "type": ".none", }, "customFields": Array [], - "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", + "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", "id": "mock-id-3", "owner": "cases", "settings": Object { @@ -561,7 +561,7 @@ describe('CasesConnectorExecutor', () => { "type": ".none", }, "customFields": Array [], - "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", + "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", "id": "mock-id-3", "owner": "cases", "settings": Object { @@ -608,7 +608,7 @@ describe('CasesConnectorExecutor', () => { casesClientMock.cases.bulkCreate.mock.calls[0][0].cases[0].description; expect(description).toMatchInlineSnapshot( - `"This case was created by the Case action in Test rule. The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`."` + `"This case was created by the case action in Test rule. The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`."` ); }); @@ -645,7 +645,7 @@ describe('CasesConnectorExecutor', () => { casesClientMock.cases.bulkCreate.mock.calls[0][0].cases[0].description; expect(description).toMatchInlineSnapshot( - `"This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`foo: [\\"bar\\",1,true,{}]\` and \`bar.foo: test\` and \`baz: my value\`."` + `"This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`foo: [\\"bar\\",1,true,{}]\` and \`bar.foo: test\` and \`baz: my value\`."` ); }); @@ -876,7 +876,7 @@ describe('CasesConnectorExecutor', () => { "type": ".none", }, "customFields": Array [], - "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", + "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", "id": "mock-id-4", "owner": "cases", "settings": Object { @@ -987,7 +987,7 @@ describe('CasesConnectorExecutor', () => { "value": false, }, ], - "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", + "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", "id": "mock-id-3", "owner": "cases", "settings": Object { @@ -1061,7 +1061,7 @@ describe('CasesConnectorExecutor', () => { "value": false, }, ], - "description": "This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", + "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", "id": "mock-id-4", "owner": "cases", "settings": Object { diff --git a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts index 12df76eabd8c8..f11a270e45c82 100644 --- a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts +++ b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts @@ -40,6 +40,12 @@ import type { CasesService } from './cases_service'; import type { CasesClient } from '../../client'; import type { BulkCreateArgs as BulkCreateAlertsReq } from '../../client/attachments/types'; import { CasesConnectorError } from './cases_connector_error'; +import { + AUTO_CREATED_TITLE, + CASE_CREATED_BY_RULE_DESC, + GROUPED_BY_DESC, + GROUPED_BY_TITLE, +} from './translations'; interface CasesConnectorExecutorParams { logger: Logger; @@ -760,8 +766,10 @@ export class CasesConnectorExecutor { .join(' & '); const suffix = `${ - groupingDescription.length > 0 ? ` - Grouping by ${groupingDescription}` : '' - }${oracleCounter > INITIAL_ORACLE_RECORD_COUNTER ? ` (${oracleCounter})` : ''} (Auto-created)`; + groupingDescription.length > 0 ? ` - ${GROUPED_BY_TITLE(groupingDescription)}` : '' + }${ + oracleCounter > INITIAL_ORACLE_RECORD_COUNTER ? ` (${oracleCounter})` : '' + } (${AUTO_CREATED_TITLE})`; const ruleNameTrimmed = params.rule.name.slice( 0, @@ -781,7 +789,7 @@ export class CasesConnectorExecutor { ? `[${params.rule.name}](${params.rule.ruleUrl})` : params.rule.name; - const description = `This case was created by the Case action in ${ruleName}.`; + const description = `${CASE_CREATED_BY_RULE_DESC(ruleName)}.`; const groupingDescription = Object.entries(grouping) .map(([key, value]) => { @@ -790,7 +798,7 @@ export class CasesConnectorExecutor { .join(' and '); if (groupingDescription.length > 0) { - return `${description} The assigned alerts are grouped by ${groupingDescription}.`; + return `${description} ${GROUPED_BY_DESC(groupingDescription)}.`; } return `${description}`; diff --git a/x-pack/plugins/cases/server/connectors/cases/translations.ts b/x-pack/plugins/cases/server/connectors/cases/translations.ts new file mode 100644 index 0000000000000..c721fe85dc9b0 --- /dev/null +++ b/x-pack/plugins/cases/server/connectors/cases/translations.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const CASE_CREATED_BY_RULE_DESC = (ruleName: string) => + i18n.translate('xpack.cases.caseAction.caseCreatedByRuleDesc', { + defaultMessage: 'This case was created by the case action in {ruleName}', + values: { + ruleName, + }, + }); + +export const GROUPED_BY_DESC = (groupingDescription: string) => + i18n.translate('xpack.cases.caseAction.groupedByDesc', { + defaultMessage: 'The assigned alerts are grouped by {groupingDescription}', + values: { + groupingDescription, + }, + }); + +export const GROUPED_BY_TITLE = (groupingDescription: string) => + i18n.translate('xpack.cases.caseAction.groupedByTitle', { + defaultMessage: 'Grouping by {groupingDescription}', + values: { + groupingDescription, + }, + }); + +export const AUTO_CREATED_TITLE = i18n.translate('xpack.cases.caseAction.autoCreatedTitle', { + defaultMessage: 'Auto-created', +}); From 18cf2d2d810624e6815cca0bf5826f849d43b005 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Tue, 16 Apr 2024 13:10:56 +0300 Subject: [PATCH 11/13] Improve rule context in description --- .../cases/cases_connector_executor.test.ts | 18 +++++++++--------- .../cases/cases_connector_executor.ts | 2 +- .../server/connectors/cases/translations.ts | 2 +- .../trial/connectors/cases/cases_connector.ts | 10 +++++----- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts index 7e51410d248ec..8d4f778d86f5b 100644 --- a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts +++ b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.test.ts @@ -252,7 +252,7 @@ describe('CasesConnectorExecutor', () => { "type": ".none", }, "customFields": Array [], - "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", + "description": "This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", "id": "mock-id-1", "owner": "cases", "settings": Object { @@ -278,7 +278,7 @@ describe('CasesConnectorExecutor', () => { "type": ".none", }, "customFields": Array [], - "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.1\`.", + "description": "This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.1\`.", "id": "mock-id-2", "owner": "cases", "settings": Object { @@ -304,7 +304,7 @@ describe('CasesConnectorExecutor', () => { "type": ".none", }, "customFields": Array [], - "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", + "description": "This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", "id": "mock-id-3", "owner": "cases", "settings": Object { @@ -561,7 +561,7 @@ describe('CasesConnectorExecutor', () => { "type": ".none", }, "customFields": Array [], - "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", + "description": "This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", "id": "mock-id-3", "owner": "cases", "settings": Object { @@ -608,7 +608,7 @@ describe('CasesConnectorExecutor', () => { casesClientMock.cases.bulkCreate.mock.calls[0][0].cases[0].description; expect(description).toMatchInlineSnapshot( - `"This case was created by the case action in Test rule. The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`."` + `"This case was created by the rule Test rule. The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`."` ); }); @@ -645,7 +645,7 @@ describe('CasesConnectorExecutor', () => { casesClientMock.cases.bulkCreate.mock.calls[0][0].cases[0].description; expect(description).toMatchInlineSnapshot( - `"This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`foo: [\\"bar\\",1,true,{}]\` and \`bar.foo: test\` and \`baz: my value\`."` + `"This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`foo: [\\"bar\\",1,true,{}]\` and \`bar.foo: test\` and \`baz: my value\`."` ); }); @@ -876,7 +876,7 @@ describe('CasesConnectorExecutor', () => { "type": ".none", }, "customFields": Array [], - "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", + "description": "This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", "id": "mock-id-4", "owner": "cases", "settings": Object { @@ -987,7 +987,7 @@ describe('CasesConnectorExecutor', () => { "value": false, }, ], - "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", + "description": "This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: B\` and \`dest.ip: 0.0.0.3\`.", "id": "mock-id-3", "owner": "cases", "settings": Object { @@ -1061,7 +1061,7 @@ describe('CasesConnectorExecutor', () => { "value": false, }, ], - "description": "This case was created by the case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", + "description": "This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id). The assigned alerts are grouped by \`host.name: A\` and \`dest.ip: 0.0.0.1\`.", "id": "mock-id-4", "owner": "cases", "settings": Object { diff --git a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts index f11a270e45c82..638477e680960 100644 --- a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts +++ b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts @@ -786,7 +786,7 @@ export class CasesConnectorExecutor { private getCaseDescription(params: CasesConnectorRunParams, grouping: GroupedAlerts['grouping']) { const ruleName = params.rule.ruleUrl - ? `[${params.rule.name}](${params.rule.ruleUrl})` + ? `['${params.rule.name}'](${params.rule.ruleUrl})` : params.rule.name; const description = `${CASE_CREATED_BY_RULE_DESC(ruleName)}.`; diff --git a/x-pack/plugins/cases/server/connectors/cases/translations.ts b/x-pack/plugins/cases/server/connectors/cases/translations.ts index c721fe85dc9b0..95e044d87eb24 100644 --- a/x-pack/plugins/cases/server/connectors/cases/translations.ts +++ b/x-pack/plugins/cases/server/connectors/cases/translations.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; export const CASE_CREATED_BY_RULE_DESC = (ruleName: string) => i18n.translate('xpack.cases.caseAction.caseCreatedByRuleDesc', { - defaultMessage: 'This case was created by the case action in {ruleName}', + defaultMessage: 'This case was created by the rule {ruleName}', values: { ruleName, }, diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/connectors/cases/cases_connector.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/connectors/cases/cases_connector.ts index 15b1b344d8338..b0fcd30fa5a42 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/connectors/cases/cases_connector.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/connectors/cases/cases_connector.ts @@ -323,7 +323,7 @@ export default ({ getService }: FtrProviderContext): void => { }, customFields: [], description: - 'This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id).', + "This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id).", duration: null, external_service: null, id: 'ee06877e50151293e75cd6c5bd81812c15c25be55ed970f91c6f7dc40e1eafa6', @@ -693,7 +693,7 @@ export default ({ getService }: FtrProviderContext): void => { }, customFields: [], description: - 'This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by `host.name: A`.', + "This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id). The assigned alerts are grouped by `host.name: A`.", duration: null, external_service: null, id: firstCaseId, @@ -740,7 +740,7 @@ export default ({ getService }: FtrProviderContext): void => { }, customFields: [], description: - 'This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by `host.name: B`.', + "This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id). The assigned alerts are grouped by `host.name: B`.", duration: null, external_service: null, id: secondCaseId, @@ -995,10 +995,10 @@ export default ({ getService }: FtrProviderContext): void => { ); expect(firstCase.description).to.be( - 'This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by `host.name: A`.' + "This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id). The assigned alerts are grouped by `host.name: A`." ); expect(secondCase.description).to.be( - 'This case was created by the Case action in [Test rule](https://example.com/rules/rule-test-id). The assigned alerts are grouped by `host.name: unknown`.' + "This case was created by the rule ['Test rule'](https://example.com/rules/rule-test-id). The assigned alerts are grouped by `host.name: unknown`." ); const firstCaseAttachments = await getAllComments({ From af0baecbd806b3643dd3265d37c0cf5e30916ebf Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Tue, 16 Apr 2024 13:12:40 +0300 Subject: [PATCH 12/13] PR feedback --- .../cases/server/connectors/cases/cases_connector_executor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts index 638477e680960..15435cc8be76c 100644 --- a/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts +++ b/x-pack/plugins/cases/server/connectors/cases/cases_connector_executor.ts @@ -801,7 +801,7 @@ export class CasesConnectorExecutor { return `${description} ${GROUPED_BY_DESC(groupingDescription)}.`; } - return `${description}`; + return description; } private getCaseTags(params: CasesConnectorRunParams, grouping: GroupedAlerts['grouping']) { From dc91440e4c97d6cb768a4b07701c802c5b165df8 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Tue, 16 Apr 2024 13:50:02 +0300 Subject: [PATCH 13/13] Fix types --- .../get_system_action_kibana_privileges.test.ts | 12 ++++++------ .../lib/validate_authorize_system_actions.test.ts | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/alerting/server/connector_adapters/get_system_action_kibana_privileges.test.ts b/x-pack/plugins/alerting/server/connector_adapters/get_system_action_kibana_privileges.test.ts index 9f5d053cbc2b3..9394f6ef6964a 100644 --- a/x-pack/plugins/alerting/server/connector_adapters/get_system_action_kibana_privileges.test.ts +++ b/x-pack/plugins/alerting/server/connector_adapters/get_system_action_kibana_privileges.test.ts @@ -45,7 +45,7 @@ describe('getSystemActionKibanaPrivileges', () => { const privileges = getSystemActionKibanaPrivileges({ connectorAdapterRegistry: registry, systemActions: [], - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }); expect(privileges).toEqual([]); @@ -54,7 +54,7 @@ describe('getSystemActionKibanaPrivileges', () => { it('should return an empty array if systemActions are not defined', () => { const privileges = getSystemActionKibanaPrivileges({ connectorAdapterRegistry: registry, - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }); expect(privileges).toEqual([]); @@ -64,7 +64,7 @@ describe('getSystemActionKibanaPrivileges', () => { const privileges = getSystemActionKibanaPrivileges({ connectorAdapterRegistry: registry, systemActions, - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }); expect(privileges).toEqual(['my-priv:stackAlerts', 'my-priv-2:stackAlerts']); @@ -74,7 +74,7 @@ describe('getSystemActionKibanaPrivileges', () => { const privileges = getSystemActionKibanaPrivileges({ connectorAdapterRegistry: registry, systemActions: [...systemActions, { id: 'my-id-2', actionTypeId: '.not-valid', params: {} }], - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }); expect(privileges).toEqual(['my-priv:stackAlerts', 'my-priv-2:stackAlerts']); @@ -84,7 +84,7 @@ describe('getSystemActionKibanaPrivileges', () => { const privileges = getSystemActionKibanaPrivileges({ connectorAdapterRegistry: registry, systemActions: [...systemActions, { id: 'my-id-2', actionTypeId: '.no-priv', params: {} }], - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }); expect(privileges).toEqual(['my-priv:stackAlerts', 'my-priv-2:stackAlerts']); @@ -94,7 +94,7 @@ describe('getSystemActionKibanaPrivileges', () => { const privileges = getSystemActionKibanaPrivileges({ connectorAdapterRegistry: registry, systemActions: [systemActions[0], systemActions[0]], - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }); expect(privileges).toEqual(['my-priv:stackAlerts']); diff --git a/x-pack/plugins/alerting/server/lib/validate_authorize_system_actions.test.ts b/x-pack/plugins/alerting/server/lib/validate_authorize_system_actions.test.ts index f69213b4f3bf2..d5aeaa3f02bbe 100644 --- a/x-pack/plugins/alerting/server/lib/validate_authorize_system_actions.test.ts +++ b/x-pack/plugins/alerting/server/lib/validate_authorize_system_actions.test.ts @@ -50,7 +50,7 @@ describe('validateAndAuthorizeSystemActions', () => { systemActions: [], actionsClient, actionsAuthorization, - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }); expect(res).toBe(undefined); @@ -78,7 +78,7 @@ describe('validateAndAuthorizeSystemActions', () => { systemActions, actionsClient, actionsAuthorization, - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }) ).rejects.toThrowErrorMatchingInlineSnapshot(`"Action not-exist is not a system action"`); }); @@ -103,7 +103,7 @@ describe('validateAndAuthorizeSystemActions', () => { systemActions, actionsClient, actionsAuthorization, - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }) ).rejects.toThrowErrorMatchingInlineSnapshot(`"Action not-exist is not a system action"`); }); @@ -128,7 +128,7 @@ describe('validateAndAuthorizeSystemActions', () => { systemActions, actionsClient, actionsAuthorization, - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Invalid system action params. System action type: .test - [foo]: expected value of type [string] but got [undefined]"` @@ -161,7 +161,7 @@ describe('validateAndAuthorizeSystemActions', () => { systemActions, actionsClient, actionsAuthorization, - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }) ).rejects.toThrowErrorMatchingInlineSnapshot(`"Cannot use the same system action twice"`); }); @@ -213,7 +213,7 @@ describe('validateAndAuthorizeSystemActions', () => { systemActions, actionsClient, actionsAuthorization, - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }); expect(res).toBe(undefined); @@ -281,7 +281,7 @@ describe('validateAndAuthorizeSystemActions', () => { systemActions, actionsClient, actionsAuthorization, - rule: { consumer: 'stackAlerts' }, + rule: { consumer: 'stackAlerts', producer: 'alerts' }, }); expect(actionsAuthorization.ensureAuthorized).toBeCalledWith({