Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solution] [Cases] Swimlane Connector for Cases #100086

Merged
merged 119 commits into from
Jun 23, 2021
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
85fe84e
Adding swimlane connector
joshswimlane Jan 4, 2021
cf2eb78
Merge branch 'master' of github.com:elastic/kibana into field_mapping…
XavierM Mar 22, 2021
3bb04dc
clean up + rm rejectUnauthorized
XavierM Mar 22, 2021
badc8f3
Merge 3bb04dc0aac098e591937592287a411de66a19fb into 639f8290ffcb28560…
XavierM Apr 28, 2021
b76f426
Merge branch 'master' of github.com:elastic/kibana into field_mapping…
XavierM Apr 29, 2021
d243b0e
Merge b76f426a86cca6bd74f45363f8858d930715158e into d111c27808e16f961…
XavierM Apr 29, 2021
9a2f02e
Merge branch 'field_mapping_connector_2' into field_mapping_connector
stephmilovic Apr 29, 2021
9c7ce14
wip
stephmilovic May 3, 2021
440fa5e
better types
stephmilovic May 3, 2021
9d9662f
cases maps
stephmilovic May 3, 2021
fa1f749
fix types
stephmilovic May 3, 2021
796712c
working on fields
stephmilovic May 4, 2021
377fd0a
can push case to swimlane
stephmilovic May 5, 2021
9384d9f
Merge branch 'master' into field_mapping_connector
stephmilovic May 12, 2021
6e699b3
working well
stephmilovic May 13, 2021
1acf2fa
fixed jest
stephmilovic May 13, 2021
19a2da7
fixing
stephmilovic May 13, 2021
e92dd16
made connector better
stephmilovic May 13, 2021
9595350
fix and add func tests
stephmilovic May 14, 2021
45be23a
Merge branch 'master' into field_mapping_connector
stephmilovic May 17, 2021
1bab00d
jsx
stephmilovic May 17, 2021
b527f54
schema fix
stephmilovic May 17, 2021
617328f
fix type in test
stephmilovic May 18, 2021
2f23cb4
Minor improvements
cnasikas May 19, 2021
b3e2ff6
Adding swimlane docs
jonathan-buttner May 19, 2021
410036e
Improve type
cnasikas May 24, 2021
060531a
Fix case connector schema
cnasikas May 24, 2021
dcaab5b
Move getApplicatio to the backend
cnasikas May 24, 2021
439ecff
Prevent prototype polution from fields
cnasikas May 24, 2021
a4f27d1
Add tests
cnasikas May 24, 2021
34dee16
Revert commit dcaab5b0f5f
cnasikas May 24, 2021
32d76d7
Fixing logout issue
jonathan-buttner May 24, 2021
a180758
Merge branch 'master' into field_mapping_connector
kibanamachine May 25, 2021
b51be9f
Minor improvements
cnasikas May 25, 2021
a532b41
Merge branch 'field_mapping_connector' of github.com:stephmilovic/kib…
cnasikas May 25, 2021
abba08c
Prevent prototype polution from fields
cnasikas May 26, 2021
e15c83c
Add description field
cnasikas May 26, 2021
97892b2
Make alert name optional
cnasikas May 26, 2021
aff1000
Change case mapping
cnasikas May 26, 2021
15e442f
Remove cases fields UI
cnasikas May 26, 2021
2a3ccf2
Delete comments from incident
cnasikas May 26, 2021
4cd8a46
Clear fields if needed
cnasikas May 27, 2021
9c28c13
Change reset to configure API
cnasikas May 27, 2021
dd1a32d
Improve components
cnasikas May 27, 2021
671b968
Merge branch 'master' into field_mapping_connector
kibanamachine May 27, 2021
d64875e
Lazy load svg icon
cnasikas May 27, 2021
bf6bdb6
Improve step status
cnasikas May 27, 2021
5f03f75
Fix params, api, & schema
cnasikas May 27, 2021
ba8c671
Create connector types
cnasikas May 31, 2021
851c880
Small fixes
cnasikas Jun 1, 2021
bf1f493
Show warning when mapping is empty
cnasikas Jun 1, 2021
ee23c03
Remove case name from fields
cnasikas Jun 1, 2021
9790343
Show connector card
cnasikas Jun 1, 2021
a2efccf
Remove unecessary code
cnasikas Jun 1, 2021
ef4f3b9
Show warning message when connector is not of type cases
cnasikas Jun 1, 2021
f28e4f5
Show warning message when connector is not of type alerts
cnasikas Jun 1, 2021
1a68b0e
Remove optional from target mapping field
cnasikas Jun 1, 2021
79c8bfd
Fix types
cnasikas Jun 1, 2021
e33403f
Improve order
cnasikas Jun 1, 2021
a237cb0
Fix tests
cnasikas Jun 1, 2021
2c39f9b
Merge branch 'master' into field_mapping_connector
kibanamachine Jun 1, 2021
fbbd762
Improve responses
cnasikas Jun 1, 2021
2c72b6d
Small fixes
cnasikas Jun 2, 2021
e9f5a57
Fix integration tests
cnasikas Jun 2, 2021
b8f2c0d
Update readme
cnasikas Jun 2, 2021
f7b8871
Switch to button group
cnasikas Jun 2, 2021
bd062c2
Better translation for required fields
cnasikas Jun 2, 2021
835f62b
Change buttons width
cnasikas Jun 2, 2021
68fc3ef
Compress buttons
cnasikas Jun 2, 2021
cc7d41f
Make case id required
cnasikas Jun 3, 2021
bc9ac93
Rename to rule name
cnasikas Jun 3, 2021
26d3523
Fix translation
cnasikas Jun 3, 2021
ed87bc4
Add alert id field
cnasikas Jun 3, 2021
2ab916b
Reorder fields
cnasikas Jun 3, 2021
d0d4f77
Fixes
cnasikas Jun 3, 2021
b283be8
Fix validation
cnasikas Jun 3, 2021
a83e7d5
Add alert id to params
cnasikas Jun 3, 2021
5edc02d
Show mapping if any of the required fields is missing
cnasikas Jun 3, 2021
e21eb4e
Add tests
cnasikas Jun 7, 2021
9f1ff56
Merge branch 'master' into field_mapping_connector
cnasikas Jun 7, 2021
0b7eeb6
Fix creation of default mapping
cnasikas Jun 7, 2021
1a98afc
Merge branch 'master' into field_mapping_connector
cnasikas Jun 9, 2021
6d29a7b
Hide alert id and alert name
cnasikas Jun 9, 2021
34e08da
Async validation
cnasikas Jun 9, 2021
d51a24f
Improve field step status
cnasikas Jun 9, 2021
63a5bb5
Fix tests
cnasikas Jun 9, 2021
4b8e2bb
Switch to http server
cnasikas Jun 9, 2021
89633e0
Merge branch 'master' into field_mapping_connector
cnasikas Jun 10, 2021
110baf2
Merge branch 'master' into field_mapping_connector
cnasikas Jun 10, 2021
3eb39e9
Switch to new mapping
cnasikas Jun 10, 2021
36aa3b8
Improve callout message
cnasikas Jun 15, 2021
f4771de
Add help text to alert source
cnasikas Jun 15, 2021
762c095
Improve helpers
cnasikas Jun 15, 2021
a8b9462
Improve tests
cnasikas Jun 15, 2021
cc5b10a
Improve messages
cnasikas Jun 15, 2021
aa79a78
Fix bug when using connector of type all
cnasikas Jun 16, 2021
2e3aa1c
Fix bug when creating connector
cnasikas Jun 16, 2021
f33ec56
Merge branch 'master' into field_mapping_connector
cnasikas Jun 16, 2021
18c37d7
Add cases_fields tests
cnasikas Jun 16, 2021
57ac290
Improve docs
cnasikas Jun 16, 2021
0e91329
Fix docs
cnasikas Jun 17, 2021
d3677d1
Remove alert source
cnasikas Jun 17, 2021
17ffdd5
Add more tests
cnasikas Jun 18, 2021
ab0fa38
Fix tests
cnasikas Jun 18, 2021
ae4a85d
Improve error message
cnasikas Jun 18, 2021
f110d0c
Merge branch 'master' into field_mapping_connector
cnasikas Jun 18, 2021
cf9a26e
Merge branch 'master' into field_mapping_connector
kibanamachine Jun 18, 2021
fc46dcf
Merge branch 'master' into field_mapping_connector
kibanamachine Jun 21, 2021
223b334
Close server after the end of tests
cnasikas Jun 22, 2021
2672be7
Add status code to error messages
cnasikas Jun 22, 2021
6f6ba26
PR feedback
cnasikas Jun 22, 2021
ae9b807
Merge branch 'field_mapping_connector' of github.com:stephmilovic/kib…
cnasikas Jun 22, 2021
c048432
Merge branch 'master' of github.com:elastic/kibana into field_mapping…
jonathan-buttner Jun 22, 2021
c129d22
Fix readme
cnasikas Jun 23, 2021
3d7d894
Add more tests for helpers
cnasikas Jun 23, 2021
72f6202
PR feedback
cnasikas Jun 23, 2021
cf6f927
Hide error message with css
cnasikas Jun 23, 2021
e16a51d
Merge branch 'field_mapping_connector' of github.com:stephmilovic/kib…
cnasikas Jun 23, 2021
2bf467a
Merge branch 'master' into field_mapping_connector
kibanamachine Jun 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions x-pack/plugins/actions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ Table of Contents
- [`subActionParams (getFields)`](#subactionparams-getfields-2)
- [`subActionParams (incidentTypes)`](#subactionparams-incidenttypes)
- [`subActionParams (severity)`](#subactionparams-severity)
- [Swimlane](#swimlane)
- [`params`](#params-3)
- [`subActionParams (pushToService)`](#subactionparams-pushtoservice-3)
- [`subActionParams (createRecord)`](#subactionparams-createRecord)
- [Command Line Utility](#command-line-utility)
- [Developing New Action Types](#developing-new-action-types)
- [licensing](#licensing)
Expand Down Expand Up @@ -394,6 +398,45 @@ No parameters for the `incidentTypes` subaction. Provide an empty object `{}`.

No parameters for the `severity` subaction. Provide an empty object `{}`.

---
## Swimlane
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This README Swimlane info looks good, but what about the rest of the connector documentation - are you going to add it in the separate PR?

Copy link
Contributor

@jonathan-buttner jonathan-buttner May 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a stab at the docs here: b3e2ff6

Is there a way to preview them so that the images load 🤔 ?



### `params`

| Property | Description | Type |
| --------------- | -------------------------------------------------------------------------------------------------- | ------ |
| subAction | The subaction to perform. It can be `pushToService` or `createRecord`. | string |
| subActionParams | The parameters of the subaction. | object |

#### `subActionParams (createRecord)`

| Property | Description | Type |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| alertName | The alert name of the incident. | string |
| alertSource | The alert source of the incident. | string _(optional)_ |
| caseId | The case id of the incident. | string _(optional)_ |
| caseName | The case name of the incident. | string _(optional)_ |
| comments | The comments of the incident. | string _(optional)_ |
| severity | The severity of the incident. | string _(optional)_ |

`subActionParams (pushToService)`

| Property | Description | Type |
| -------- | ------------------------------------------------------------------------------------------------------------- | --------------------- |
| incident | The Swimlane incident. | object |
| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }`. | object[] _(optional)_ |

The following table describes the properties of the `incident` object.

| Property | Description | Type |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| alertName | The alert name of the incident. | string |
| alertSource | The alert source of the incident. | string _(optional)_ |
| caseId | The case id of the incident. | string _(optional)_ |
| caseName | The case name of the incident. | string _(optional)_ |
| comments | The comments of the incident. | string _(optional)_ |
| severity | The severity of the incident.
---
# Command Line Utility

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const ACTION_TYPE_IDS = [
'.pagerduty',
'.server-log',
'.slack',
'.swimlane',
'.teams',
'.webhook',
];
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/actions/server/builtin_action_types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Logger } from '../../../../../src/core/server';
import { getActionType as getEmailActionType } from './email';
import { getActionType as getIndexActionType } from './es_index';
import { getActionType as getPagerDutyActionType } from './pagerduty';
import { getActionType as getSwimlaneActionType } from './swimlane';
import { getActionType as getServerLogActionType } from './server_log';
import { getActionType as getSlackActionType } from './slack';
import { getActionType as getWebhookActionType } from './webhook';
Expand Down Expand Up @@ -65,6 +66,7 @@ export function registerBuiltInActionTypes({
);
actionTypeRegistry.register(getIndexActionType({ logger }));
actionTypeRegistry.register(getPagerDutyActionType({ logger, configurationUtilities }));
actionTypeRegistry.register(getSwimlaneActionType({ logger, configurationUtilities }));
actionTypeRegistry.register(getServerLogActionType({ logger }));
actionTypeRegistry.register(getSlackActionType({ logger, configurationUtilities }));
actionTypeRegistry.register(getWebhookActionType({ logger, configurationUtilities }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,6 @@ export const ExternalIncidentServiceSecretConfigurationSchema = schema.object(
ExternalIncidentServiceSecretConfiguration
);

export const ExecutorSubActionSchema = schema.oneOf([
cnasikas marked this conversation as resolved.
Show resolved Hide resolved
schema.literal('getIncident'),
schema.literal('pushToService'),
schema.literal('handshake'),
schema.literal('issueTypes'),
schema.literal('fieldsByIssueType'),
]);

export const ExecutorSubActionPushParamsSchema = schema.object({
incident: schema.object({
summary: schema.string(),
Expand Down
10 changes: 5 additions & 5 deletions x-pack/plugins/actions/server/builtin_action_types/jira/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ import {
ExecutorSubActionGetIncidentParamsSchema,
ExecutorSubActionHandshakeParamsSchema,
ExecutorSubActionGetCapabilitiesParamsSchema,
ExecutorSubActionGetIssueTypesParamsSchema,
ExecutorSubActionGetFieldsByIssueTypeParamsSchema,
ExecutorSubActionGetIssuesParamsSchema,
ExecutorSubActionGetIssueParamsSchema,
ExecutorSubActionCommonFieldsParamsSchema,
} from './schema';
import { ActionsConfigurationUtilities } from '../../actions_config';
import { Logger } from '../../../../../../src/core/server';
Expand Down Expand Up @@ -124,8 +124,8 @@ export type ExecutorSubActionGetCapabilitiesParams = TypeOf<
typeof ExecutorSubActionGetCapabilitiesParamsSchema
>;

export type ExecutorSubActionGetIssueTypesParams = TypeOf<
typeof ExecutorSubActionGetIssueTypesParamsSchema
export type ExecutorSubActionCommonFieldsParams = TypeOf<
typeof ExecutorSubActionCommonFieldsParamsSchema
>;

export type ExecutorSubActionGetFieldsByIssueTypeParams = TypeOf<
Expand Down Expand Up @@ -157,12 +157,12 @@ export interface HandshakeApiHandlerArgs extends ExternalServiceApiHandlerArgs {

export interface GetIssueTypesHandlerArgs {
externalService: ExternalService;
params: ExecutorSubActionGetIssueTypesParams;
params: ExecutorSubActionCommonFieldsParams;
}

export interface GetCommonFieldsHandlerArgs {
externalService: ExternalService;
params: ExecutorSubActionGetIssueTypesParams;
params: ExecutorSubActionCommonFieldsParams;
}

export interface GetFieldsByIssueTypeHandlerArgs {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,6 @@ export const ExternalIncidentServiceSecretConfigurationSchema = schema.object(
ExternalIncidentServiceSecretConfiguration
);

export const ExecutorSubActionSchema = schema.oneOf([
cnasikas marked this conversation as resolved.
Show resolved Hide resolved
schema.literal('getIncident'),
schema.literal('pushToService'),
schema.literal('handshake'),
schema.literal('incidentTypes'),
schema.literal('severity'),
]);

export const ExecutorSubActionPushParamsSchema = schema.object({
incident: schema.object({
name: schema.string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,6 @@ export const ExternalIncidentServiceSecretConfigurationSchema = schema.object(
ExternalIncidentServiceSecretConfiguration
);

export const ExecutorSubActionSchema = schema.oneOf([
cnasikas marked this conversation as resolved.
Show resolved Hide resolved
schema.literal('getFields'),
schema.literal('getIncident'),
schema.literal('pushToService'),
schema.literal('handshake'),
schema.literal('getChoices'),
]);

const CommentsSchema = schema.nullable(
schema.arrayOf(
schema.object({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* 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 { api } from './api';
import { ExternalService } from './types';
import { externalServiceMock, recordResponseCreate, recordResponseUpdate } from './mocks';
import { Logger } from '@kbn/logging';
let mockedLogger: jest.Mocked<Logger>;
const params = {
alertName: 'alert name',
caseName: 'case name',
severity: 'critical',
alertSource: 'elastic',
caseId: '123456',
comments: 'some comments',
};
describe('api', () => {
let externalService: jest.Mocked<ExternalService>;

beforeEach(() => {
externalService = externalServiceMock.create();
});

describe('createRecord', () => {
test('it creates a record correctly with a comment', async () => {
const res = await api.createRecord({
externalService,
logger: mockedLogger,
params: {
alertName: 'alert name',
caseName: 'case name',
severity: 'critical',
alertSource: 'elastic',
caseId: '123456',
comments: 'some comments',
},
});
expect(res).toEqual(recordResponseCreate);
});
});

describe('pushToService', () => {
test('it pushes a new record', async () => {
const res = await api.pushToService({
externalService,
logger: mockedLogger,
params: {
incident: {
...params,
externalId: null,
},
comments: [],
},
});
expect(externalService.createComment).not.toHaveBeenCalled();
expect(externalService.createRecord).toHaveBeenCalled();
expect(externalService.updateRecord).not.toHaveBeenCalled();
expect(res).toEqual(recordResponseCreate);
});
test('it pushes a new record with a comment', async () => {
await api.pushToService({
externalService,
logger: mockedLogger,
params: {
incident: {
...params,
externalId: null,
},
comments: [{ comment: 'some comments', commentId: '123' }],
},
});
expect(externalService.createComment).toHaveBeenCalled();
});
test('updates existing record', async () => {
const res = await api.pushToService({
externalService,
logger: mockedLogger,
params: {
incident: {
...params,
externalId: '1234',
},
comments: [{ comment: 'some comments', commentId: '123' }],
},
});
expect(externalService.createComment).toHaveBeenCalled();
expect(externalService.createRecord).not.toHaveBeenCalled();
expect(externalService.updateRecord).toHaveBeenCalled();
expect(res).toEqual(recordResponseUpdate);
});
});
});
57 changes: 57 additions & 0 deletions x-pack/plugins/actions/server/builtin_action_types/swimlane/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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 {
CreateRecordApiHandlerArgs,
ExternalServiceIncidentResponse,
ExternalServiceApi,
Incident,
PushToServiceApiHandlerArgs,
} from './types';

const createRecordHandler = async ({
externalService,
params,
}: CreateRecordApiHandlerArgs): Promise<ExternalServiceIncidentResponse> => {
return await externalService.createRecord({ incident: { ...params, externalId: null } });
};

const pushToServiceHandler = async ({
externalService,
params,
}: PushToServiceApiHandlerArgs): Promise<ExternalServiceIncidentResponse> => {
const { comments } = params;
let res: ExternalServiceIncidentResponse;
const incident: Incident = params.incident;
if (incident.externalId != null) {
res = await externalService.updateRecord({
incidentId: incident.externalId,
incident,
});
} else {
res = await externalService.createRecord({ incident });
}

const createdDate = new Date().toISOString();

if (comments && Array.isArray(comments) && comments.length > 0) {
for (const currentComment of comments) {
await externalService.createComment({
incidentId: res.id,
comment: currentComment,
createdDate,
});
}
}

return res;
};

export const api: ExternalServiceApi = {
createRecord: createRecordHandler,
pushToService: pushToServiceHandler,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 { MappingConfigType } from './types';
import { getBodyForEventAction } from './helpers';

describe('Create Record Mapping', () => {
let mappingConfig: MappingConfigType;
const appId = '45678';

beforeAll(() => {
mappingConfig = {
alertSourceConfig: {
id: 'adnjls',
name: 'Alert Source',
key: 'alert-source',
fieldType: 'text',
},
severityConfig: {
id: 'adnlas',
name: 'Severity',
key: 'severity',
fieldType: 'text',
},
alertNameConfig: {
id: 'adnfls',
name: 'Alert Name',
key: 'alert-name',
fieldType: 'text',
},
caseIdConfig: {
id: 'a6sst',
name: 'Case Id',
key: 'case-id-name',
fieldType: 'text',
},
caseNameConfig: {
id: 'a6fst',
name: 'Case Name',
key: 'case-name',
fieldType: 'text',
},
commentsConfig: {
id: 'a6fdf',
name: 'Comments',
key: 'comments',
fieldType: 'text',
},
};
});

test('Mapping is Successful', () => {
const params = {
alertName: 'Alert Name',
severity: 'Critical',
alertSource: 'Elastic',
caseName: 'Case Name',
caseId: 'es3456789',
comments: 'This is a comment',
externalId: null,
};
const data = getBodyForEventAction(appId, mappingConfig, params);
expect(data?.values?.[mappingConfig.alertSourceConfig?.id ?? 0]).toEqual(params.alertSource);
expect(data?.values?.[mappingConfig.alertNameConfig.id]).toEqual(params.alertName);
// @ts-ignore
expect(data?.values?.[mappingConfig.caseNameConfig.id]).toEqual(params.caseName);
expect(data?.values?.[mappingConfig.caseIdConfig?.id ?? 0]).toEqual(params.caseId);
// @ts-ignore
expect(data?.values?.[mappingConfig.commentsConfig.id]).toEqual(params.comments);
expect(data?.values?.[mappingConfig?.severityConfig?.id ?? 0]).toEqual(params.severity);
});
});
Loading