From c77ae9c6ca5f44765597251757da01126072d4cd Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Wed, 17 Feb 2021 15:14:34 +0200 Subject: [PATCH 1/4] Fix alert push --- .../plugins/case/server/client/cases/mock.ts | 9 +++++ .../case/server/client/cases/utils.test.ts | 37 ++++++++----------- .../plugins/case/server/client/cases/utils.ts | 32 +++++++++++++--- .../server/routes/api/cases/push_case.test.ts | 2 +- .../connectors/servicenow/translations.ts | 2 +- 5 files changed, 54 insertions(+), 28 deletions(-) diff --git a/x-pack/plugins/case/server/client/cases/mock.ts b/x-pack/plugins/case/server/client/cases/mock.ts index 809c4ad1ea1bd..f488195c19b8e 100644 --- a/x-pack/plugins/case/server/client/cases/mock.ts +++ b/x-pack/plugins/case/server/client/cases/mock.ts @@ -11,6 +11,7 @@ import { ConnectorMappingsAttributes, CaseUserActionsResponse, AssociationType, + CommentResponseAlertsType, } from '../../../common/api'; import { BasicParams } from './types'; @@ -76,6 +77,14 @@ export const commentAlert: CommentResponse = { version: 'WzEsMV0=', }; +export const commentAlertMultipleIds: CommentResponseAlertsType = { + ...commentAlert, + id: 'mock-comment-2', + alertId: ['alert-id-1', 'alert-id-2'], + index: 'alert-index-1', + type: CommentType.alert as const, +}; + export const defaultPipes = ['informationCreated']; export const basicParams: BasicParams = { description: 'a description', diff --git a/x-pack/plugins/case/server/client/cases/utils.test.ts b/x-pack/plugins/case/server/client/cases/utils.test.ts index 361d0fb561afd..f6f457ae78835 100644 --- a/x-pack/plugins/case/server/client/cases/utils.test.ts +++ b/x-pack/plugins/case/server/client/cases/utils.test.ts @@ -17,6 +17,7 @@ import { basicParams, userActions, commentAlert, + commentAlertMultipleIds, } from './mock'; import { @@ -48,7 +49,7 @@ describe('utils', () => { { actionType: 'overwrite', key: 'short_description', - pipes: ['informationCreated'], + pipes: [], value: 'a title', }, { @@ -71,7 +72,7 @@ describe('utils', () => { { actionType: 'overwrite', key: 'short_description', - pipes: ['myTestPipe'], + pipes: [], value: 'a title', }, { @@ -98,7 +99,7 @@ describe('utils', () => { }); expect(res).toEqual({ - short_description: 'a title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'a title', description: 'a description (created at 2020-03-13T08:34:53.450Z by Elastic User)', }); }); @@ -122,13 +123,13 @@ describe('utils', () => { }, fields, currentIncident: { - short_description: 'first title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'first title', description: 'first description (created at 2020-03-13T08:34:53.450Z by Elastic User)', }, }); expect(res).toEqual({ - short_description: 'a title (updated at 2020-03-15T08:34:53.450Z by Another User)', + short_description: 'a title', description: 'first description (created at 2020-03-13T08:34:53.450Z by Elastic User) \r\na description (updated at 2020-03-15T08:34:53.450Z by Another User)', }); @@ -168,7 +169,7 @@ describe('utils', () => { }); expect(res).toEqual({ - short_description: 'a title (created at 2020-03-13T08:34:53.450Z by elastic)', + short_description: 'a title', description: 'a description (created at 2020-03-13T08:34:53.450Z by elastic)', }); }); @@ -190,7 +191,7 @@ describe('utils', () => { }); expect(res).toEqual({ - short_description: 'a title (updated at 2020-03-15T08:34:53.450Z by anotherUser)', + short_description: 'a title', description: 'a description (updated at 2020-03-15T08:34:53.450Z by anotherUser)', }); }); @@ -448,8 +449,7 @@ describe('utils', () => { labels: ['defacement'], issueType: null, parent: null, - short_description: - 'Super Bad Security Issue (created at 2019-11-25T21:54:48.952Z by elastic)', + short_description: 'Super Bad Security Issue', description: 'This is a brand new case of a bad meanie defacing data (created at 2019-11-25T21:54:48.952Z by elastic)', externalId: null, @@ -504,7 +504,7 @@ describe('utils', () => { expect(res.comments).toEqual([]); }); - it('it creates comments of type alert correctly', async () => { + it('it adds the total alert comments correctly', async () => { const res = await createIncident({ actionsClient: actionsMock, theCase: { @@ -512,7 +512,9 @@ describe('utils', () => { comments: [ { ...commentObj, id: 'comment-user-1' }, { ...commentAlert, id: 'comment-alert-1' }, - { ...commentAlert, id: 'comment-alert-2' }, + { + ...commentAlertMultipleIds, + }, ], }, // Remove second push @@ -536,14 +538,8 @@ describe('utils', () => { commentId: 'comment-user-1', }, { - comment: - 'Alert with ids alert-id-1 added to case (added at 2019-11-25T21:55:00.177Z by elastic)', - commentId: 'comment-alert-1', - }, - { - comment: - 'Alert with ids alert-id-1 added to case (added at 2019-11-25T21:55:00.177Z by elastic)', - commentId: 'comment-alert-2', + comment: 'Elastic Security Alerts attached to the case: 3', + commentId: '', }, ]); }); @@ -578,8 +574,7 @@ describe('utils', () => { description: 'fun description \r\nThis is a brand new case of a bad meanie defacing data (updated at 2019-11-25T21:54:48.952Z by elastic)', externalId: 'external-id', - short_description: - 'Super Bad Security Issue (updated at 2019-11-25T21:54:48.952Z by elastic)', + short_description: 'Super Bad Security Issue', }, comments: [], }); diff --git a/x-pack/plugins/case/server/client/cases/utils.ts b/x-pack/plugins/case/server/client/cases/utils.ts index fda4142bf77c7..6b3f365af449d 100644 --- a/x-pack/plugins/case/server/client/cases/utils.ts +++ b/x-pack/plugins/case/server/client/cases/utils.ts @@ -152,20 +152,36 @@ export const createIncident = async ({ userActions .slice(latestPushInfo?.index ?? 0) .filter( - (action, index) => - Array.isArray(action.action_field) && action.action_field[0] === 'comment' + (action) => Array.isArray(action.action_field) && action.action_field[0] === 'comment' ) .map((action) => action.comment_id) ); - const commentsToBeUpdated = caseComments?.filter((comment) => - commentsIdsToBeUpdated.has(comment.id) + + const commentsToBeUpdated = caseComments?.filter( + (comment) => + // We push only user's comments + comment.type === CommentType.user && commentsIdsToBeUpdated.has(comment.id) ); + const totalAlerts = + caseComments?.reduce((total, comment) => { + if (comment.type === CommentType.alert || comment.type === CommentType.generatedAlert) { + return total + (Array.isArray(comment.alertId) ? comment.alertId.length : 1); + } + return total; + }, 0) ?? 0; + let comments: ExternalServiceComment[] = []; if (commentsToBeUpdated && Array.isArray(commentsToBeUpdated) && commentsToBeUpdated.length > 0) { const commentsMapping = mappings.find((m) => m.source === 'comments'); if (commentsMapping?.action_type !== 'nothing') { comments = transformComments(commentsToBeUpdated, ['informationAdded']); + if (totalAlerts > 0) { + comments.push({ + comment: `Elastic Security Alerts attached to the case: ${totalAlerts}`, + commentId: '', + }); + } } } return { incident, comments }; @@ -247,7 +263,13 @@ export const prepareFieldsForTransformation = ({ key: mapping.target, value: params[mapping.source] ?? '', actionType: mapping.action_type, - pipes: mapping.action_type === 'append' ? [...defaultPipes, 'append'] : defaultPipes, + pipes: + // Do not transform titles + mapping.source !== 'title' + ? mapping.action_type === 'append' + ? [...defaultPipes, 'append'] + : defaultPipes + : [], }, ] : acc, diff --git a/x-pack/plugins/case/server/routes/api/cases/push_case.test.ts b/x-pack/plugins/case/server/routes/api/cases/push_case.test.ts index bf398d1ffcf40..c8501130493ba 100644 --- a/x-pack/plugins/case/server/routes/api/cases/push_case.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/push_case.test.ts @@ -170,7 +170,7 @@ describe('Push case', () => { parent: null, priority: 'High', labels: ['LOLBins'], - summary: 'Another bad one (created at 2019-11-25T22:32:17.947Z by elastic)', + summary: 'Another bad one', description: 'Oh no, a bad meanie going LOLBins all over the place! (created at 2019-11-25T22:32:17.947Z by elastic)', externalId: null, diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/translations.ts b/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/translations.ts index 0867dc41eeb78..77c263385df0a 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/translations.ts +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/translations.ts @@ -87,7 +87,7 @@ export const PRIORITY = i18n.translate( export const ALERT_FIELDS_LABEL = i18n.translate( 'xpack.securitySolution.components.connectors.serviceNow.alertFieldsTitle', { - defaultMessage: 'Fields associated with alerts', + defaultMessage: 'Select Observables to push', } ); From 70075bd592ebbb25271b43760581fa6c2432444b Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Wed, 17 Feb 2021 18:56:37 +0200 Subject: [PATCH 2/4] Fix bug --- x-pack/plugins/case/server/client/cases/utils.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/case/server/client/cases/utils.ts b/x-pack/plugins/case/server/client/cases/utils.ts index 6b3f365af449d..712780da2d756 100644 --- a/x-pack/plugins/case/server/client/cases/utils.ts +++ b/x-pack/plugins/case/server/client/cases/utils.ts @@ -172,18 +172,21 @@ export const createIncident = async ({ }, 0) ?? 0; let comments: ExternalServiceComment[] = []; + if (commentsToBeUpdated && Array.isArray(commentsToBeUpdated) && commentsToBeUpdated.length > 0) { const commentsMapping = mappings.find((m) => m.source === 'comments'); if (commentsMapping?.action_type !== 'nothing') { comments = transformComments(commentsToBeUpdated, ['informationAdded']); - if (totalAlerts > 0) { - comments.push({ - comment: `Elastic Security Alerts attached to the case: ${totalAlerts}`, - commentId: '', - }); - } } } + + if (totalAlerts > 0) { + comments.push({ + comment: `Elastic Security Alerts attached to the case: ${totalAlerts}`, + commentId: '', + }); + } + return { incident, comments }; }; From ff64ec2d339a9af8e14662c9a11a892a9eebeffe Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Wed, 24 Feb 2021 17:20:11 +0200 Subject: [PATCH 3/4] PR feedback --- .../plugins/case/server/client/cases/types.ts | 2 +- .../plugins/case/server/client/cases/utils.ts | 33 ++++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/case/server/client/cases/types.ts b/x-pack/plugins/case/server/client/cases/types.ts index f1d56e7132bd1..2dd2caf9fe73a 100644 --- a/x-pack/plugins/case/server/client/cases/types.ts +++ b/x-pack/plugins/case/server/client/cases/types.ts @@ -72,7 +72,7 @@ export interface TransformFieldsArgs { export interface ExternalServiceComment { comment: string; - commentId: string; + commentId?: string; } export interface MapIncident { diff --git a/x-pack/plugins/case/server/client/cases/utils.ts b/x-pack/plugins/case/server/client/cases/utils.ts index 712780da2d756..a5013d9b93982 100644 --- a/x-pack/plugins/case/server/client/cases/utils.ts +++ b/x-pack/plugins/case/server/client/cases/utils.ts @@ -40,6 +40,15 @@ import { } from './types'; import { getAlertIds } from '../../routes/api/utils'; +interface CreateIncidentArgs { + actionsClient: ActionsClient; + theCase: CaseResponse; + userActions: CaseUserActionsResponse; + connector: ActionConnector; + mappings: ConnectorMappingsAttributes[]; + alerts: CaseClientGetAlertsResponse; +} + export const getLatestPushInfo = ( connectorId: string, userActions: CaseUserActionsResponse @@ -75,14 +84,13 @@ const getCommentContent = (comment: CommentResponse): string => { return ''; }; -interface CreateIncidentArgs { - actionsClient: ActionsClient; - theCase: CaseResponse; - userActions: CaseUserActionsResponse; - connector: ActionConnector; - mappings: ConnectorMappingsAttributes[]; - alerts: CaseClientGetAlertsResponse; -} +const countAlerts = (comments: CaseResponse['comments']): number => + comments?.reduce((total, comment) => { + if (comment.type === CommentType.alert || comment.type === CommentType.generatedAlert) { + return total + (Array.isArray(comment.alertId) ? comment.alertId.length : 1); + } + return total; + }, 0) ?? 0; export const createIncident = async ({ actionsClient, @@ -163,13 +171,7 @@ export const createIncident = async ({ comment.type === CommentType.user && commentsIdsToBeUpdated.has(comment.id) ); - const totalAlerts = - caseComments?.reduce((total, comment) => { - if (comment.type === CommentType.alert || comment.type === CommentType.generatedAlert) { - return total + (Array.isArray(comment.alertId) ? comment.alertId.length : 1); - } - return total; - }, 0) ?? 0; + const totalAlerts = countAlerts(caseComments); let comments: ExternalServiceComment[] = []; @@ -183,7 +185,6 @@ export const createIncident = async ({ if (totalAlerts > 0) { comments.push({ comment: `Elastic Security Alerts attached to the case: ${totalAlerts}`, - commentId: '', }); } From c0172bd3d9f1245f8bc83abee62f020293c15a4d Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Wed, 24 Feb 2021 18:51:48 +0200 Subject: [PATCH 4/4] Add tests --- .../plugins/case/server/client/cases/mock.ts | 6 ++++ .../case/server/client/cases/utils.test.ts | 31 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/case/server/client/cases/mock.ts b/x-pack/plugins/case/server/client/cases/mock.ts index f488195c19b8e..490519187f49e 100644 --- a/x-pack/plugins/case/server/client/cases/mock.ts +++ b/x-pack/plugins/case/server/client/cases/mock.ts @@ -85,6 +85,12 @@ export const commentAlertMultipleIds: CommentResponseAlertsType = { type: CommentType.alert as const, }; +export const commentGeneratedAlert: CommentResponseAlertsType = { + ...commentAlertMultipleIds, + id: 'mock-comment-3', + type: CommentType.generatedAlert as const, +}; + export const defaultPipes = ['informationCreated']; export const basicParams: BasicParams = { description: 'a description', diff --git a/x-pack/plugins/case/server/client/cases/utils.test.ts b/x-pack/plugins/case/server/client/cases/utils.test.ts index f6f457ae78835..44e7a682aa7ed 100644 --- a/x-pack/plugins/case/server/client/cases/utils.test.ts +++ b/x-pack/plugins/case/server/client/cases/utils.test.ts @@ -18,6 +18,7 @@ import { userActions, commentAlert, commentAlertMultipleIds, + commentGeneratedAlert, } from './mock'; import { @@ -539,7 +540,35 @@ describe('utils', () => { }, { comment: 'Elastic Security Alerts attached to the case: 3', - commentId: '', + }, + ]); + }); + + it('it removes alerts correctly', async () => { + const res = await createIncident({ + actionsClient: actionsMock, + theCase: { + ...theCase, + comments: [ + { ...commentObj, id: 'comment-user-1' }, + commentAlertMultipleIds, + commentGeneratedAlert, + ], + }, + userActions, + connector, + mappings, + alerts: [], + }); + + expect(res.comments).toEqual([ + { + comment: + 'Wow, good luck catching that bad meanie! (added at 2019-11-25T21:55:00.177Z by elastic)', + commentId: 'comment-user-1', + }, + { + comment: 'Elastic Security Alerts attached to the case: 4', }, ]); });