Skip to content

Commit b14ab29

Browse files
committed
[Cases] Improve connectors mapping (#101145)
1 parent 5e4c549 commit b14ab29

39 files changed

Lines changed: 516 additions & 1121 deletions

x-pack/plugins/cases/common/api/connectors/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export enum ConnectorTypes {
3838
none = '.none',
3939
}
4040

41+
export const connectorTypes = Object.values(ConnectorTypes);
42+
4143
const ConnectorJiraTypeFieldsRt = rt.type({
4244
type: rt.literal(ConnectorTypes.jira),
4345
fields: rt.union([JiraFieldsRT, rt.null]),

x-pack/plugins/cases/public/components/configure_cases/mapping.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('Mapping', () => {
5050
wrappingComponent: TestProviders,
5151
});
5252
expect(wrapper.find('[data-test-subj="field-mapping-desc"]').first().text()).toBe(
53-
'Field mappings require an established connection to ServiceNow ITSM. Please check your connection credentials.'
53+
'Failed to retrieve mappings for ServiceNow ITSM.'
5454
);
5555
});
5656
});

x-pack/plugins/cases/public/components/configure_cases/translations.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,7 @@ export const FIELD_MAPPING_DESC = (thirdPartyName: string): string => {
102102
export const FIELD_MAPPING_DESC_ERR = (thirdPartyName: string): string => {
103103
return i18n.translate('xpack.cases.configureCases.fieldMappingDescErr', {
104104
values: { thirdPartyName },
105-
defaultMessage:
106-
'Field mappings require an established connection to { thirdPartyName }. Please check your connection credentials.',
105+
defaultMessage: 'Failed to retrieve mappings for { thirdPartyName }.',
107106
});
108107
};
109108
export const EDIT_FIELD_MAPPING_TITLE = (thirdPartyName: string): string => {

x-pack/plugins/cases/server/client/cases/push.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { createCaseError, flattenCaseSavedObject, getAlertInfoFromComments } fro
2525
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
2626
import { CasesClient, CasesClientArgs, CasesClientInternal } from '..';
2727
import { Operations } from '../../authorization';
28+
import { casesConnectors } from '../../connectors';
2829

2930
/**
3031
* Returns true if the case should be closed based on the configuration settings and whether the case
@@ -110,8 +111,7 @@ export const push = async (
110111
});
111112

112113
const connectorMappings = await casesClientInternal.configuration.getMappings({
113-
connectorId: connector.id,
114-
connectorType: connector.actionTypeId,
114+
connector: theCase.connector,
115115
});
116116

117117
if (connectorMappings.length === 0) {
@@ -125,6 +125,7 @@ export const push = async (
125125
connector: connector as ActionConnector,
126126
mappings: connectorMappings[0].attributes.mappings,
127127
alerts,
128+
casesConnectors,
128129
});
129130

130131
const pushRes = await actionsClient.execute({

x-pack/plugins/cases/server/client/cases/utils.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
} from './utils';
3131
import { flattenCaseSavedObject } from '../../common';
3232
import { SECURITY_SOLUTION_OWNER } from '../../../common';
33+
import { casesConnectors } from '../../connectors';
3334

3435
const formatComment = {
3536
commentId: commentObj.id,
@@ -443,6 +444,7 @@ describe('utils', () => {
443444
connector,
444445
mappings,
445446
alerts: [],
447+
casesConnectors,
446448
});
447449

448450
expect(res).toEqual({
@@ -471,6 +473,7 @@ describe('utils', () => {
471473
connector,
472474
mappings,
473475
alerts: [],
476+
casesConnectors,
474477
});
475478

476479
expect(res.comments).toEqual([
@@ -501,6 +504,7 @@ describe('utils', () => {
501504
},
502505
],
503506
alerts: [],
507+
casesConnectors,
504508
});
505509

506510
expect(res.comments).toEqual([]);
@@ -531,6 +535,7 @@ describe('utils', () => {
531535
},
532536
],
533537
alerts: [],
538+
casesConnectors,
534539
});
535540

536541
expect(res.comments).toEqual([
@@ -561,6 +566,7 @@ describe('utils', () => {
561566
connector,
562567
mappings,
563568
alerts: [],
569+
casesConnectors,
564570
});
565571

566572
expect(res.comments).toEqual([
@@ -595,6 +601,7 @@ describe('utils', () => {
595601
connector,
596602
mappings,
597603
alerts: [],
604+
casesConnectors,
598605
});
599606

600607
expect(res).toEqual({
@@ -626,6 +633,7 @@ describe('utils', () => {
626633
connector,
627634
mappings,
628635
alerts: [],
636+
casesConnectors,
629637
}).catch((e) => {
630638
expect(e).not.toBeNull();
631639
expect(e).toEqual(
@@ -645,6 +653,7 @@ describe('utils', () => {
645653
connector: { ...connector, actionTypeId: 'not-supported' },
646654
mappings,
647655
alerts: [],
656+
casesConnectors,
648657
}).catch((e) => {
649658
expect(e).not.toBeNull();
650659
expect(e).toEqual(new Error('Invalid external service'));

x-pack/plugins/cases/server/client/cases/utils.ts

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,15 @@ import {
1212
CaseFullExternalService,
1313
CaseResponse,
1414
CaseUserActionsResponse,
15-
CommentAttributes,
16-
CommentRequestAlertType,
17-
CommentRequestUserType,
1815
CommentResponse,
1916
CommentResponseAlertsType,
2017
CommentType,
2118
ConnectorMappingsAttributes,
22-
ConnectorTypes,
19+
CommentAttributes,
20+
CommentRequestUserType,
21+
CommentRequestAlertType,
2322
} from '../../../common';
2423
import { ActionsClient } from '../../../../actions/server';
25-
import { externalServiceFormatters, FormatterConnectorTypes } from '../../connectors';
2624
import { CasesClientGetAlertsResponse } from '../../client/alerts/types';
2725
import {
2826
BasicParams,
@@ -39,6 +37,7 @@ import {
3937
TransformFieldsArgs,
4038
} from './types';
4139
import { getAlertIds } from '../utils';
40+
import { CasesConnectorsMap } from '../../connectors';
4241

4342
interface CreateIncidentArgs {
4443
actionsClient: ActionsClient;
@@ -47,6 +46,7 @@ interface CreateIncidentArgs {
4746
connector: ActionConnector;
4847
mappings: ConnectorMappingsAttributes[];
4948
alerts: CasesClientGetAlertsResponse;
49+
casesConnectors: CasesConnectorsMap;
5050
}
5151

5252
export const getLatestPushInfo = (
@@ -70,9 +70,6 @@ export const getLatestPushInfo = (
7070
return null;
7171
};
7272

73-
const isConnectorSupported = (connectorId: string): connectorId is FormatterConnectorTypes =>
74-
Object.values(ConnectorTypes).includes(connectorId as ConnectorTypes);
75-
7673
const getCommentContent = (comment: CommentResponse): string => {
7774
if (comment.type === CommentType.user) {
7875
return comment.comment;
@@ -99,6 +96,7 @@ export const createIncident = async ({
9996
connector,
10097
mappings,
10198
alerts,
99+
casesConnectors,
102100
}: CreateIncidentArgs): Promise<MapIncident> => {
103101
const {
104102
comments: caseComments,
@@ -110,20 +108,15 @@ export const createIncident = async ({
110108
updated_by: updatedBy,
111109
} = theCase;
112110

113-
if (!isConnectorSupported(connector.actionTypeId)) {
114-
throw new Error('Invalid external service');
115-
}
116-
117111
const params = { title, description, createdAt, createdBy, updatedAt, updatedBy };
118112
const latestPushInfo = getLatestPushInfo(connector.id, userActions);
119113
const externalId = latestPushInfo?.pushedInfo?.external_id ?? null;
120114
const defaultPipes = externalId ? ['informationUpdated'] : ['informationCreated'];
121115
let currentIncident: ExternalServiceParams | undefined;
122116

123-
const externalServiceFields = externalServiceFormatters[connector.actionTypeId].format(
124-
theCase,
125-
alerts
126-
);
117+
const externalServiceFields =
118+
casesConnectors.get(connector.actionTypeId)?.format(theCase, alerts) ?? {};
119+
127120
let incident: Partial<PushToServiceApiParams['incident']> = { ...externalServiceFields };
128121

129122
if (externalId) {

x-pack/plugins/cases/server/client/configure/client.ts

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import {
2626
excess,
2727
GetConfigureFindRequest,
2828
GetConfigureFindRequestRt,
29-
GetFieldsResponse,
3029
throwErrors,
3130
CasesConfigurationsResponse,
3231
CaseConfigurationsResponseRt,
@@ -41,20 +40,14 @@ import {
4140
} from '../../common';
4241
import { CasesClientInternal } from '../client_internal';
4342
import { CasesClientArgs } from '../types';
44-
import { getFields } from './get_fields';
4543
import { getMappings } from './get_mappings';
4644

4745
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
4846
import { FindActionResult } from '../../../../actions/server/types';
4947
import { ActionType } from '../../../../actions/common';
5048
import { Operations } from '../../authorization';
5149
import { combineAuthorizedAndOwnerFilter } from '../utils';
52-
import {
53-
ConfigurationGetFields,
54-
MappingsArgs,
55-
CreateMappingsArgs,
56-
UpdateMappingsArgs,
57-
} from './types';
50+
import { MappingsArgs, CreateMappingsArgs, UpdateMappingsArgs } from './types';
5851
import { createMappings } from './create_mappings';
5952
import { updateMappings } from './update_mappings';
6053
import {
@@ -69,7 +62,6 @@ import {
6962
* @ignore
7063
*/
7164
export interface InternalConfigureSubClient {
72-
getFields(params: ConfigurationGetFields): Promise<GetFieldsResponse>;
7365
getMappings(
7466
params: MappingsArgs
7567
): Promise<SavedObjectsFindResponse<ConnectorMappings>['saved_objects']>;
@@ -116,12 +108,9 @@ export const createInternalConfigurationSubClient = (
116108
casesClientInternal: CasesClientInternal
117109
): InternalConfigureSubClient => {
118110
const configureSubClient: InternalConfigureSubClient = {
119-
getFields: (params: ConfigurationGetFields) => getFields(params, clientArgs),
120111
getMappings: (params: MappingsArgs) => getMappings(params, clientArgs),
121-
createMappings: (params: CreateMappingsArgs) =>
122-
createMappings(params, clientArgs, casesClientInternal),
123-
updateMappings: (params: UpdateMappingsArgs) =>
124-
updateMappings(params, clientArgs, casesClientInternal),
112+
createMappings: (params: CreateMappingsArgs) => createMappings(params, clientArgs),
113+
updateMappings: (params: UpdateMappingsArgs) => updateMappings(params, clientArgs),
125114
};
126115

127116
return Object.freeze(configureSubClient);
@@ -194,8 +183,7 @@ async function get(
194183
if (connector != null) {
195184
try {
196185
mappings = await casesClientInternal.configuration.getMappings({
197-
connectorId: connector.id,
198-
connectorType: connector.type,
186+
connector: transformESConnectorToCaseConnector(connector),
199187
});
200188
} catch (e) {
201189
error = e.isBoom
@@ -303,32 +291,32 @@ async function update(
303291

304292
try {
305293
const resMappings = await casesClientInternal.configuration.getMappings({
306-
connectorId: connector != null ? connector.id : configuration.attributes.connector.id,
307-
connectorType: connector != null ? connector.type : configuration.attributes.connector.type,
294+
connector:
295+
connector != null
296+
? connector
297+
: transformESConnectorToCaseConnector(configuration.attributes.connector),
308298
});
309299
mappings = resMappings.length > 0 ? resMappings[0].attributes.mappings : [];
310300

311301
if (connector != null) {
312302
if (resMappings.length !== 0) {
313303
mappings = await casesClientInternal.configuration.updateMappings({
314-
connectorId: connector.id,
315-
connectorType: connector.type,
304+
connector,
316305
mappingId: resMappings[0].id,
317306
});
318307
} else {
319308
mappings = await casesClientInternal.configuration.createMappings({
320-
connectorId: connector.id,
321-
connectorType: connector.type,
309+
connector,
322310
owner: configuration.attributes.owner,
323311
});
324312
}
325313
}
326314
} catch (e) {
327315
error = e.isBoom
328316
? e.output.payload.message
329-
: `Error connecting to ${
317+
: `Error creating mapping for ${
330318
connector != null ? connector.name : configuration.attributes.connector.name
331-
} instance`;
319+
}`;
332320
}
333321

334322
const patch = await caseConfigureService.patch({
@@ -429,14 +417,13 @@ async function create(
429417

430418
try {
431419
mappings = await casesClientInternal.configuration.createMappings({
432-
connectorId: configuration.connector.id,
433-
connectorType: configuration.connector.type,
420+
connector: configuration.connector,
434421
owner: configuration.owner,
435422
});
436423
} catch (e) {
437424
error = e.isBoom
438425
? e.output.payload.message
439-
: `Error connecting to ${configuration.connector.name} instance`;
426+
: `Error creating mapping for ${configuration.connector.name}`;
440427
}
441428

442429
const post = await caseConfigureService.post({

x-pack/plugins/cases/server/client/configure/create_mappings.ts

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,41 @@
55
* 2.0.
66
*/
77

8-
import { ConnectorMappingsAttributes, ConnectorTypes } from '../../../common/api';
8+
import { ConnectorMappingsAttributes } from '../../../common/api';
99
import { ACTION_SAVED_OBJECT_TYPE } from '../../../../actions/server';
1010
import { createCaseError } from '../../common/error';
11-
import { CasesClientArgs, CasesClientInternal } from '..';
11+
import { CasesClientArgs } from '..';
1212
import { CreateMappingsArgs } from './types';
13+
import { casesConnectors } from '../../connectors';
1314

1415
export const createMappings = async (
15-
{ connectorType, connectorId, owner }: CreateMappingsArgs,
16-
clientArgs: CasesClientArgs,
17-
casesClientInternal: CasesClientInternal
16+
{ connector, owner }: CreateMappingsArgs,
17+
clientArgs: CasesClientArgs
1818
): Promise<ConnectorMappingsAttributes[]> => {
1919
const { unsecuredSavedObjectsClient, connectorMappingsService, logger } = clientArgs;
2020

2121
try {
22-
if (connectorType === ConnectorTypes.none) {
23-
return [];
24-
}
25-
26-
const res = await casesClientInternal.configuration.getFields({
27-
connectorId,
28-
connectorType,
29-
});
22+
const mappings = casesConnectors.get(connector.type)?.getMapping() ?? [];
3023

3124
const theMapping = await connectorMappingsService.post({
3225
unsecuredSavedObjectsClient,
3326
attributes: {
34-
mappings: res.defaultMappings,
27+
mappings,
3528
owner,
3629
},
3730
references: [
3831
{
3932
type: ACTION_SAVED_OBJECT_TYPE,
4033
name: `associated-${ACTION_SAVED_OBJECT_TYPE}`,
41-
id: connectorId,
34+
id: connector.id,
4235
},
4336
],
4437
});
4538

4639
return theMapping.attributes.mappings;
4740
} catch (error) {
4841
throw createCaseError({
49-
message: `Failed to create mapping connector id: ${connectorId} type: ${connectorType}: ${error}`,
42+
message: `Failed to create mapping connector id: ${connector.id} type: ${connector.type}: ${error}`,
5043
error,
5144
logger,
5245
});

0 commit comments

Comments
 (0)