From 306a7426235ec295e079a86745e076cd497a08ff Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Fri, 30 Oct 2020 08:41:36 -0600 Subject: [PATCH 01/13] notes --- x-pack/plugins/actions/server/builtin_action_types/jira/api.ts | 1 + x-pack/plugins/actions/server/builtin_action_types/jira/index.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts index 679c1541964ce..34cb7bbd0dfe9 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts @@ -83,6 +83,7 @@ const pushToServiceHandler = async ({ } let incident: Incident; + // TO DO STEPH // TODO: should be removed later but currently keep it for the Case implementation support if (mapping) { const fields = prepareFieldsForTransformation({ diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts index 9d6ff90c33700..f306cbdaae3f9 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts @@ -113,6 +113,7 @@ async function executor( const { comments, externalId, ...restParams } = pushToServiceParams; const incidentConfiguration = config.incidentConfiguration; + // TO DO STEPH const mapping = incidentConfiguration ? buildMap(incidentConfiguration.mapping) : null; const externalObject = config.incidentConfiguration && mapping From 083b4e5c341a9cd0d667aed8ab31664915beca08 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Fri, 30 Oct 2020 13:42:47 -0600 Subject: [PATCH 02/13] got fields for jira --- .../server/builtin_action_types/jira/api.ts | 6 +++ .../server/builtin_action_types/jira/index.ts | 8 +++ .../builtin_action_types/jira/schema.ts | 4 ++ .../builtin_action_types/jira/service.ts | 49 ++++++++++++++++++- .../server/builtin_action_types/jira/types.ts | 41 +++++++++++++--- 5 files changed, 99 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts index 34cb7bbd0dfe9..c9ee15ecb0222 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts @@ -39,6 +39,11 @@ const getIssueTypesHandler = async ({ externalService }: GetIssueTypesHandlerArg return res; }; +const getCommonFieldsHandler = async ({ externalService }: GetIssueTypesHandlerArgs) => { + const res = await externalService.getCommonFields(); + return res; +}; + const getFieldsByIssueTypeHandler = async ({ externalService, params, @@ -158,6 +163,7 @@ const pushToServiceHandler = async ({ }; export const api: ExternalServiceApi = { + commonFields: getCommonFieldsHandler, handshake: handshakeHandler, pushToService: pushToServiceHandler, getIncident: getIncidentHandler, diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts index f306cbdaae3f9..4fae1874f2ac1 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts @@ -40,6 +40,7 @@ interface GetActionTypeParams { } const supportedSubActions: string[] = [ + 'commonFields', 'pushToService', 'issueTypes', 'fieldsByIssueType', @@ -146,6 +147,13 @@ async function executor( }); } + if (subAction === 'commonFields') { + data = await api.commonFields({ + externalService, + params: subActionParams, + }); + } + if (subAction === 'issues') { const getIssuesParams = subActionParams as ExecutorSubActionGetIssuesParams; data = await api.issues({ diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts index 513ca2cf18e6c..eac871f0aff4b 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts @@ -65,6 +65,10 @@ export const ExecutorSubActionGetIssuesParamsSchema = schema.object({ title: sch export const ExecutorSubActionGetIssueParamsSchema = schema.object({ id: schema.string() }); export const ExecutorParamsSchema = schema.oneOf([ + schema.object({ + subAction: schema.literal('commonFields'), + subActionParams: ExecutorSubActionGetIssueTypesParamsSchema, + }), schema.object({ subAction: schema.literal('getIncident'), subActionParams: ExecutorSubActionGetIncidentParamsSchema, diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts index f5347891f4f70..0873dfc39abf9 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts @@ -20,6 +20,7 @@ import { ResponseError, ExternalServiceCommentResponse, ExternalServiceIncidentResponse, + ExternalServiceFields, } from './types'; import * as i18n from './translations'; @@ -46,6 +47,7 @@ export const createExternalService = ( throw Error(`[Action]${i18n.NAME}: Wrong configuration.`); } + const fieldsUrl = `${url}/${BASE_URL}/field`; const incidentUrl = `${url}/${BASE_URL}/issue`; const capabilitiesUrl = `${url}/${CAPABILITIES_URL}`; const commentUrl = `${incidentUrl}/{issueId}/comment`; @@ -150,6 +152,28 @@ export const createExternalService = ( title: issue.fields?.summary ?? null, }); + const getFields = async (): Promise => { + try { + const res = await request({ + axios: axiosInstance, + url: fieldsUrl, + logger, + proxySettings, + }); + + return res.data; + } catch (error) { + throw new Error( + getErrorMessage( + i18n.NAME, + `Unable to get fields from Jira. Error: ${error.message} Reason: ${createErrorMessage( + error.response?.data + )}` + ) + ); + } + }; + const getIncident = async (id: string) => { try { const res = await request({ @@ -326,7 +350,6 @@ export const createExternalService = ( const getIssueTypes = async () => { const capabilitiesResponse = await getCapabilities(); const supportsNewAPI = hasSupportForNewAPI(capabilitiesResponse); - try { if (!supportsNewAPI) { const res = await request({ @@ -409,6 +432,29 @@ export const createExternalService = ( } }; + const getCommonFields = async () => { + const fields = await getFields(); + const issueTypes = await getIssueTypes(); + const fieldTypes = await Promise.all( + issueTypes.map((issueType) => getFieldsByIssueType(issueType.id)) + ); + const commonFields = fieldTypes.reduce((acc: string[], fieldTypesByIssue) => { + const newKeys = Object.keys(fieldTypesByIssue); + if (acc.length === 0) { + return [...newKeys]; + } + acc.forEach((key) => { + newKeys.includes(key); + if (!newKeys.includes(key)) { + acc = acc.filter((e) => e !== key); + } + }); + return acc; + }, []); + const fieldDetails = fields.filter((f) => commonFields.includes(f.id)); + return fieldDetails; + }; + const getIssues = async (title: string) => { const query = `${searchUrl}?jql=${encodeURIComponent( `project="${projectKey}" and summary ~"${title}"` @@ -461,6 +507,7 @@ export const createExternalService = ( }; return { + getCommonFields, getIncident, createIncident, updateIncident, diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts index 7d650a22fba1b..0fab15b4f6301 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts @@ -79,6 +79,24 @@ export interface CreateCommentParams { comment: Comment; } +export interface FieldsSchema { + type: string; + [key: string]: string; +} + +export interface ExternalServiceFields { + clauseNames: string[]; + custom: boolean; + id: string; + key: string; + name: string; + navigatable: boolean; + orderable: boolean; + schema: FieldsSchema; + searchable: boolean; +} +export type GetCommonFieldsResponse = ExternalServiceFields[]; + export type GetIssueTypesResponse = Array<{ id: string; name: string }>; export type GetFieldsByIssueTypeResponse = Record< string, @@ -93,15 +111,16 @@ export interface GetIssueResponse { } export interface ExternalService { - getIncident: (id: string) => Promise; - createIncident: (params: CreateIncidentParams) => Promise; - updateIncident: (params: UpdateIncidentParams) => Promise; createComment: (params: CreateCommentParams) => Promise; + createIncident: (params: CreateIncidentParams) => Promise; + getCommonFields: () => Promise; getCapabilities: () => Promise; - getIssueTypes: () => Promise; getFieldsByIssueType: (issueTypeId: string) => Promise; - getIssues: (title: string) => Promise; + getIncident: (id: string) => Promise; getIssue: (id: string) => Promise; + getIssues: (title: string) => Promise; + getIssueTypes: () => Promise; + updateIncident: (params: UpdateIncidentParams) => Promise; } export interface PushToServiceApiParams extends ExecutorSubActionPushParams { @@ -157,6 +176,11 @@ export interface GetIssueTypesHandlerArgs { params: ExecutorSubActionGetIssueTypesParams; } +export interface GetCommonFieldsHandlerArgs { + externalService: ExternalService; + params: ExecutorSubActionGetIssueTypesParams; +} + export interface GetFieldsByIssueTypeHandlerArgs { externalService: ExternalService; params: ExecutorSubActionGetFieldsByIssueTypeParams; @@ -177,15 +201,16 @@ export interface GetIssueHandlerArgs { } export interface ExternalServiceApi { - handshake: (args: HandshakeApiHandlerArgs) => Promise; - pushToService: (args: PushToServiceApiHandlerArgs) => Promise; + commonFields: (args: GetIssueTypesHandlerArgs) => Promise; getIncident: (args: GetIncidentApiHandlerArgs) => Promise; + handshake: (args: HandshakeApiHandlerArgs) => Promise; issueTypes: (args: GetIssueTypesHandlerArgs) => Promise; + pushToService: (args: PushToServiceApiHandlerArgs) => Promise; fieldsByIssueType: ( args: GetFieldsByIssueTypeHandlerArgs ) => Promise; - issues: (args: GetIssuesHandlerArgs) => Promise; issue: (args: GetIssueHandlerArgs) => Promise; + issues: (args: GetIssuesHandlerArgs) => Promise; } export type JiraExecutorResultData = From 09cf519ab62d5c5249c2a529ea277e98a7d7db8e Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Fri, 30 Oct 2020 13:52:45 -0600 Subject: [PATCH 03/13] better --- .../server/builtin_action_types/jira/service.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts index 0873dfc39abf9..f0dfac6ab1064 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts @@ -443,16 +443,9 @@ export const createExternalService = ( if (acc.length === 0) { return [...newKeys]; } - acc.forEach((key) => { - newKeys.includes(key); - if (!newKeys.includes(key)) { - acc = acc.filter((e) => e !== key); - } - }); - return acc; + return acc.reduce((add: string[], key) => (newKeys.includes(key) ? [...add, key] : add), []); }, []); - const fieldDetails = fields.filter((f) => commonFields.includes(f.id)); - return fieldDetails; + return fields.filter((f) => commonFields.includes(f.id)); }; const getIssues = async (title: string) => { From 574db7107df459e49886499f7241629c110b7f08 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Mon, 2 Nov 2020 13:05:59 -0700 Subject: [PATCH 04/13] resilient fields --- .../server/builtin_action_types/jira/api.ts | 3 +- .../builtin_action_types/jira/schema.ts | 3 +- .../server/builtin_action_types/jira/types.ts | 2 +- .../builtin_action_types/resilient/api.ts | 10 ++++-- .../builtin_action_types/resilient/index.ts | 16 ++++++++- .../builtin_action_types/resilient/schema.ts | 5 +++ .../builtin_action_types/resilient/service.ts | 22 ++++++++++-- .../builtin_action_types/resilient/types.ts | 35 +++++++++++++++---- 8 files changed, 80 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts index c9ee15ecb0222..97e5080bfa882 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts @@ -17,6 +17,7 @@ import { PushToServiceApiParams, PushToServiceResponse, GetIssueHandlerArgs, + GetCommonFieldsHandlerArgs, } from './types'; // TODO: to remove, need to support Case @@ -39,7 +40,7 @@ const getIssueTypesHandler = async ({ externalService }: GetIssueTypesHandlerArg return res; }; -const getCommonFieldsHandler = async ({ externalService }: GetIssueTypesHandlerArgs) => { +const getCommonFieldsHandler = async ({ externalService }: GetCommonFieldsHandlerArgs) => { const res = await externalService.getCommonFields(); return res; }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts index eac871f0aff4b..a95387f390d08 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts @@ -55,6 +55,7 @@ export const ExecutorSubActionGetIncidentParamsSchema = schema.object({ }); // Reserved for future implementation +export const ExecutorSubActionCommonFieldsParamsSchema = schema.object({}); export const ExecutorSubActionHandshakeParamsSchema = schema.object({}); export const ExecutorSubActionGetCapabilitiesParamsSchema = schema.object({}); export const ExecutorSubActionGetIssueTypesParamsSchema = schema.object({}); @@ -67,7 +68,7 @@ export const ExecutorSubActionGetIssueParamsSchema = schema.object({ id: schema. export const ExecutorParamsSchema = schema.oneOf([ schema.object({ subAction: schema.literal('commonFields'), - subActionParams: ExecutorSubActionGetIssueTypesParamsSchema, + subActionParams: ExecutorSubActionCommonFieldsParamsSchema, }), schema.object({ subAction: schema.literal('getIncident'), diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts index 0fab15b4f6301..685f1f5352049 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts @@ -201,7 +201,7 @@ export interface GetIssueHandlerArgs { } export interface ExternalServiceApi { - commonFields: (args: GetIssueTypesHandlerArgs) => Promise; + commonFields: (args: GetCommonFieldsHandlerArgs) => Promise; getIncident: (args: GetIncidentApiHandlerArgs) => Promise; handshake: (args: HandshakeApiHandlerArgs) => Promise; issueTypes: (args: GetIssueTypesHandlerArgs) => Promise; diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/api.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/api.ts index 46d9c114297a9..1dd936962d1f5 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/api.ts @@ -15,6 +15,7 @@ import { GetSeverityHandlerArgs, PushToServiceApiParams, PushToServiceResponse, + GetCommonFieldsHandlerArgs, } from './types'; // TODO: to remove, need to support Case @@ -32,6 +33,10 @@ const getIncidentHandler = async ({ params, }: GetIncidentApiHandlerArgs) => {}; +const getCommonFieldsHandler = async ({ externalService }: GetCommonFieldsHandlerArgs) => { + const res = await externalService.getCommonFields(); + return res; +}; const getIncidentTypesHandler = async ({ externalService }: GetIncidentTypesHandlerArgs) => { const res = await externalService.getIncidentTypes(); return res; @@ -136,9 +141,10 @@ const pushToServiceHandler = async ({ }; export const api: ExternalServiceApi = { - handshake: handshakeHandler, - pushToService: pushToServiceHandler, + commonFields: getCommonFieldsHandler, getIncident: getIncidentHandler, + handshake: handshakeHandler, incidentTypes: getIncidentTypesHandler, + pushToService: pushToServiceHandler, severity: getSeverityHandler, }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/index.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/index.ts index 53285a2a350af..13e0cf4fe2205 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/index.ts @@ -25,6 +25,7 @@ import { ResilientExecutorResultData, ExecutorSubActionGetIncidentTypesParams, ExecutorSubActionGetSeverityParams, + ExecutorSubActionCommonFieldsParams, } from './types'; import * as i18n from './translations'; import { Logger } from '../../../../../../src/core/server'; @@ -37,7 +38,12 @@ interface GetActionTypeParams { configurationUtilities: ActionsConfigurationUtilities; } -const supportedSubActions: string[] = ['pushToService', 'incidentTypes', 'severity']; +const supportedSubActions: string[] = [ + 'commonFields', + 'pushToService', + 'incidentTypes', + 'severity', +]; // action type definition export function getActionType( @@ -122,6 +128,14 @@ async function executor( logger.debug(`response push to service for incident id: ${data.id}`); } + if (subAction === 'commonFields') { + const commonFieldsParams = subActionParams as ExecutorSubActionCommonFieldsParams; + data = await api.commonFields({ + externalService, + params: commonFieldsParams, + }); + } + if (subAction === 'incidentTypes') { const incidentTypesParams = subActionParams as ExecutorSubActionGetIncidentTypesParams; data = await api.incidentTypes({ diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/schema.ts index b6e3a9525dfd4..aadd59e60e471 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/schema.ts @@ -53,11 +53,16 @@ export const ExecutorSubActionGetIncidentParamsSchema = schema.object({ }); // Reserved for future implementation +export const ExecutorSubActionCommonFieldsParamsSchema = schema.object({}); export const ExecutorSubActionHandshakeParamsSchema = schema.object({}); export const ExecutorSubActionGetIncidentTypesParamsSchema = schema.object({}); export const ExecutorSubActionGetSeverityParamsSchema = schema.object({}); export const ExecutorParamsSchema = schema.oneOf([ + schema.object({ + subAction: schema.literal('commonFields'), + subActionParams: ExecutorSubActionCommonFieldsParamsSchema, + }), schema.object({ subAction: schema.literal('getIncident'), subActionParams: ExecutorSubActionGetIncidentParamsSchema, diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts index 4bf1453641e42..f0ae7868daf94 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts @@ -303,12 +303,28 @@ export const createExternalService = ( } }; + const getCommonFields = async () => { + try { + const res = await request({ + axios: axiosInstance, + method: 'get', + url: incidentFieldsUrl, + logger, + proxySettings, + }); + return res.data ?? []; + } catch (error) { + throw new Error(getErrorMessage(i18n.NAME, `Unable to get fields. Error: ${error.message}.`)); + } + }; + return { - getIncident, - createIncident, - updateIncident, createComment, + createIncident, + getCommonFields, + getIncident, getIncidentTypes, getSeverity, + updateIncident, }; }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/types.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/types.ts index ed622ee473b65..28269828fbae4 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/types.ts @@ -8,14 +8,15 @@ import { TypeOf } from '@kbn/config-schema'; import { - ExternalIncidentServiceConfigurationSchema, - ExternalIncidentServiceSecretConfigurationSchema, ExecutorParamsSchema, - ExecutorSubActionPushParamsSchema, + ExecutorSubActionCommonFieldsParamsSchema, ExecutorSubActionGetIncidentParamsSchema, - ExecutorSubActionHandshakeParamsSchema, ExecutorSubActionGetIncidentTypesParamsSchema, ExecutorSubActionGetSeverityParamsSchema, + ExecutorSubActionHandshakeParamsSchema, + ExecutorSubActionPushParamsSchema, + ExternalIncidentServiceConfigurationSchema, + ExternalIncidentServiceSecretConfigurationSchema, } from './schema'; import { ActionsConfigurationUtilities } from '../../actions_config'; @@ -31,6 +32,10 @@ export type ResilientSecretConfigurationType = TypeOf< typeof ExternalIncidentServiceSecretConfigurationSchema >; +export type ExecutorSubActionCommonFieldsParams = TypeOf< + typeof ExecutorSubActionCommonFieldsParamsSchema +>; + export type ExecutorParams = TypeOf; export type ExecutorSubActionPushParams = TypeOf; @@ -60,6 +65,14 @@ export interface ExternalServiceCommentResponse { } export type ExternalServiceParams = Record; +export interface ExternalServiceFields { + id: string; + input_type: string; + name: string; + read_only: boolean; + required?: string; +} +export type GetCommonFieldsResponse = ExternalServiceFields[]; export type Incident = Pick< ExecutorSubActionPushParams, @@ -86,12 +99,13 @@ export type GetIncidentTypesResponse = Array<{ id: string; name: string }>; export type GetSeverityResponse = Array<{ id: string; name: string }>; export interface ExternalService { - getIncident: (id: string) => Promise; - createIncident: (params: CreateIncidentParams) => Promise; - updateIncident: (params: UpdateIncidentParams) => Promise; createComment: (params: CreateCommentParams) => Promise; + createIncident: (params: CreateIncidentParams) => Promise; + getCommonFields: () => Promise; + getIncident: (id: string) => Promise; getIncidentTypes: () => Promise; getSeverity: () => Promise; + updateIncident: (params: UpdateIncidentParams) => Promise; } export interface PushToServiceApiParams extends ExecutorSubActionPushParams { @@ -132,6 +146,11 @@ export interface HandshakeApiHandlerArgs extends ExternalServiceApiHandlerArgs { params: ExecutorSubActionHandshakeParams; } +export interface GetCommonFieldsHandlerArgs { + externalService: ExternalService; + params: ExecutorSubActionCommonFieldsParams; +} + export interface GetIncidentTypesHandlerArgs { externalService: ExternalService; params: ExecutorSubActionGetIncidentTypesParams; @@ -147,6 +166,7 @@ export interface PushToServiceResponse extends ExternalServiceIncidentResponse { } export interface ExternalServiceApi { + commonFields: (args: GetCommonFieldsHandlerArgs) => Promise; handshake: (args: HandshakeApiHandlerArgs) => Promise; pushToService: (args: PushToServiceApiHandlerArgs) => Promise; getIncident: (args: GetIncidentApiHandlerArgs) => Promise; @@ -156,6 +176,7 @@ export interface ExternalServiceApi { export type ResilientExecutorResultData = | PushToServiceResponse + | GetCommonFieldsResponse | GetIncidentTypesResponse | GetSeverityResponse; From 8fa765d4cd22e7f6b4d2b91a71a02a35747d4578 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Mon, 2 Nov 2020 14:27:13 -0700 Subject: [PATCH 05/13] added servicenow --- .../builtin_action_types/servicenow/api.ts | 12 +++++++- .../builtin_action_types/servicenow/index.ts | 18 ++++++++--- .../builtin_action_types/servicenow/schema.ts | 6 ++++ .../servicenow/service.ts | 25 ++++++++++++++-- .../builtin_action_types/servicenow/types.ts | 30 +++++++++++++++++-- 5 files changed, 81 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts index 6d12a3c92dac7..3b58546668284 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts @@ -12,6 +12,8 @@ import { PushToServiceApiParams, PushToServiceResponse, Incident, + GetCommonFieldsHandlerArgs, + GetCommonFieldsResponse, } from './types'; // TODO: to remove, need to support Case @@ -127,8 +129,16 @@ const pushToServiceHandler = async ({ return res; }; +const getCommonFieldsHandler = async ({ + externalService, +}: GetCommonFieldsHandlerArgs): Promise => { + const res = await externalService.getCommonFields(); + return res; +}; + export const api: ExternalServiceApi = { + commonFields: getCommonFieldsHandler, + getIncident: getIncidentHandler, handshake: handshakeHandler, pushToService: pushToServiceHandler, - getIncident: getIncidentHandler, }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts index 41a577918b18e..f0b34821ad720 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts @@ -25,6 +25,8 @@ import { ServiceNowPublicConfigurationType, ServiceNowSecretConfigurationType, PushToServiceResponse, + ExecutorSubActionCommonFieldsParams, + ServiceNowExecutorResultData, } from './types'; // TODO: to remove, need to support Case @@ -63,7 +65,7 @@ export function getActionType( } // action executor - +const supportedSubActions: string[] = ['commonFields', 'pushToService']; async function executor( { logger }: { logger: Logger }, execOptions: ActionTypeExecutorOptions< @@ -71,10 +73,10 @@ async function executor( ServiceNowSecretConfigurationType, ExecutorParams > -): Promise> { +): Promise> { const { actionId, config, params, secrets } = execOptions; const { subAction, subActionParams } = params; - let data: PushToServiceResponse | null = null; + let data: ServiceNowExecutorResultData | null = null; const externalService = createExternalService( { @@ -91,7 +93,7 @@ async function executor( throw new Error(errorMessage); } - if (subAction !== 'pushToService') { + if (!supportedSubActions.includes(subAction)) { const errorMessage = `[Action][ExternalService] subAction ${subAction} not implemented.`; logger.error(errorMessage); throw new Error(errorMessage); @@ -117,5 +119,13 @@ async function executor( logger.debug(`response push to service for incident id: ${data.id}`); } + if (subAction === 'commonFields') { + const commonFieldsParams = subActionParams as ExecutorSubActionCommonFieldsParams; + data = await api.commonFields({ + externalService, + params: commonFieldsParams, + }); + } + return { status: 'ok', data: data ?? {}, actionId }; } diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts index 0dd70ea36636e..f6b89b793b990 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts @@ -28,6 +28,7 @@ export const ExternalIncidentServiceSecretConfigurationSchema = schema.object( ); export const ExecutorSubActionSchema = schema.oneOf([ + schema.literal('commonFields'), schema.literal('getIncident'), schema.literal('pushToService'), schema.literal('handshake'), @@ -53,8 +54,13 @@ export const ExecutorSubActionGetIncidentParamsSchema = schema.object({ // Reserved for future implementation export const ExecutorSubActionHandshakeParamsSchema = schema.object({}); +export const ExecutorSubActionCommonFieldsParamsSchema = schema.object({}); export const ExecutorParamsSchema = schema.oneOf([ + schema.object({ + subAction: schema.literal('commonFields'), + subActionParams: ExecutorSubActionCommonFieldsParamsSchema, + }), schema.object({ subAction: schema.literal('getIncident'), subActionParams: ExecutorSubActionGetIncidentParamsSchema, diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts index 9b1da4b4007c6..eeea79eed09de 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts @@ -16,6 +16,7 @@ import { ProxySettings } from '../../types'; const API_VERSION = 'v2'; const INCIDENT_URL = `api/now/${API_VERSION}/table/incident`; +const SYS_DICTIONARY = `api/now/${API_VERSION}/table/sys_dictionary`; // Based on: https://docs.servicenow.com/bundle/orlando-platform-user-interface/page/use/navigation/reference/r_NavigatingByURLExamples.html const VIEW_INCIDENT_URL = `nav_to.do?uri=incident.do?sys_id=`; @@ -33,6 +34,7 @@ export const createExternalService = ( } const incidentUrl = `${url}/${INCIDENT_URL}`; + const fieldsUrl = `${url}/${SYS_DICTIONARY}?sysparm_query=name=task^internal_type=string&active=true&read_only=false&sysparm_fields=max_length,element,column_label`; const axiosInstance = axios.create({ auth: { username, password }, }); @@ -126,10 +128,29 @@ export const createExternalService = ( } }; + const getCommonFields = async () => { + try { + const res = await request({ + axios: axiosInstance, + url: fieldsUrl, + logger, + proxySettings, + method: 'get', + }); + + return res.data.result.length > 0 ? { ...res.data.result } : undefined; + } catch (error) { + throw new Error( + getErrorMessage(i18n.NAME, `Unable to find incidents by query. Error: ${error.message}`) + ); + } + }; + return { - getIncident, createIncident, - updateIncident, findIncidents, + getCommonFields, + getIncident, + updateIncident, }; }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts index a6a0ac946fe96..76026358d530b 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts @@ -8,12 +8,13 @@ import { TypeOf } from '@kbn/config-schema'; import { - ExternalIncidentServiceConfigurationSchema, - ExternalIncidentServiceSecretConfigurationSchema, ExecutorParamsSchema, - ExecutorSubActionPushParamsSchema, + ExecutorSubActionCommonFieldsParamsSchema, ExecutorSubActionGetIncidentParamsSchema, ExecutorSubActionHandshakeParamsSchema, + ExecutorSubActionPushParamsSchema, + ExternalIncidentServiceConfigurationSchema, + ExternalIncidentServiceSecretConfigurationSchema, } from './schema'; import { ActionsConfigurationUtilities } from '../../actions_config'; import { ExternalServiceCommentResponse } from '../case/types'; @@ -27,6 +28,12 @@ export type ServiceNowSecretConfigurationType = TypeOf< typeof ExternalIncidentServiceSecretConfigurationSchema >; +export type ExecutorSubActionCommonFieldsParams = TypeOf< + typeof ExecutorSubActionCommonFieldsParamsSchema +>; + +export type ServiceNowExecutorResultData = PushToServiceResponse | GetCommonFieldsResponse; + export interface CreateCommentRequest { [key: string]: string; } @@ -59,6 +66,7 @@ export interface PushToServiceResponse extends ExternalServiceIncidentResponse { export type ExternalServiceParams = Record; export interface ExternalService { + getCommonFields: () => Promise; getIncident: (id: string) => Promise; createIncident: (params: ExternalServiceParams) => Promise; updateIncident: (params: ExternalServiceParams) => Promise; @@ -102,8 +110,24 @@ export interface GetIncidentApiHandlerArgs extends ExternalServiceApiHandlerArgs export interface HandshakeApiHandlerArgs extends ExternalServiceApiHandlerArgs { params: ExecutorSubActionHandshakeParams; } +export interface ExternalServiceFields { + column_label: string; + name: string; + internal_type: { + link: string; + value: string; + }; + max_length: string; + element: string; +} +export type GetCommonFieldsResponse = ExternalServiceFields[]; +export interface GetCommonFieldsHandlerArgs { + externalService: ExternalService; + params: ExecutorSubActionCommonFieldsParams; +} export interface ExternalServiceApi { + commonFields: (args: GetCommonFieldsHandlerArgs) => Promise; handshake: (args: HandshakeApiHandlerArgs) => Promise; pushToService: (args: PushToServiceApiHandlerArgs) => Promise; getIncident: (args: GetIncidentApiHandlerArgs) => Promise; From 8b82073003c2f082eadec58a789b09d48c969425 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Mon, 2 Nov 2020 14:29:34 -0700 Subject: [PATCH 06/13] small fix --- .../actions/server/builtin_action_types/servicenow/service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts index eeea79eed09de..ebef85ddb3357 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts @@ -138,10 +138,10 @@ export const createExternalService = ( method: 'get', }); - return res.data.result.length > 0 ? { ...res.data.result } : undefined; + return res.data.result.length > 0 ? res.data.result : []; } catch (error) { throw new Error( - getErrorMessage(i18n.NAME, `Unable to find incidents by query. Error: ${error.message}`) + getErrorMessage(i18n.NAME, `Unable to get incident fields. Error: ${error.message}`) ); } }; From 089f8c076b363562214536051225cd7a3745da3c Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Tue, 3 Nov 2020 14:57:42 -0700 Subject: [PATCH 07/13] add tests --- .../builtin_action_types/jira/api.test.ts | 1490 ++++++++--------- .../server/builtin_action_types/jira/mocks.ts | 72 +- .../builtin_action_types/jira/service.test.ts | 126 +- .../builtin_action_types/jira/service.ts | 32 +- .../builtin_action_types/resilient/mocks.ts | 267 +++ .../resilient/service.test.ts | 45 +- .../builtin_action_types/resilient/service.ts | 1 - .../servicenow/api.test.ts | 1215 +++++++------- .../builtin_action_types/servicenow/mocks.ts | 28 + .../servicenow/service.test.ts | 39 +- .../servicenow/service.ts | 3 +- 11 files changed, 1916 insertions(+), 1402 deletions(-) diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts index e8fa9f76df778..aff071eb88f26 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts @@ -5,7 +5,7 @@ */ import { Logger } from '../../../../../../src/core/server'; -import { externalServiceMock, mapping, apiParams } from './mocks'; +import { externalServiceMock, mapping, apiParams, jiraCommonFields } from './mocks'; import { ExternalService } from './types'; import { api } from './api'; let mockedLogger: jest.Mocked; @@ -15,804 +15,802 @@ describe('api', () => { beforeEach(() => { externalService = externalServiceMock.create(); - jest.clearAllMocks(); }); - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('pushToService', () => { - describe('create incident - cases', () => { - test('it creates an incident', async () => { - const params = { ...apiParams, externalId: null }; - const res = await api.pushToService({ - externalService, - mapping, - params, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-1', - title: 'CK-1', - pushedDate: '2020-04-27T10:59:46.202Z', - url: 'https://siem-kibana.atlassian.net/browse/CK-1', - comments: [ - { - commentId: 'case-comment-1', - pushedDate: '2020-04-27T10:59:46.202Z', - }, - { - commentId: 'case-comment-2', - pushedDate: '2020-04-27T10:59:46.202Z', - }, - ], - }); - }); - - test('it creates an incident without comments', async () => { - const params = { ...apiParams, externalId: null, comments: [] }; - const res = await api.pushToService({ - externalService, - mapping, - params, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-1', - title: 'CK-1', - pushedDate: '2020-04-27T10:59:46.202Z', - url: 'https://siem-kibana.atlassian.net/browse/CK-1', - }); - }); - - test('it calls createIncident correctly', async () => { - const params = { ...apiParams, externalId: null }; - await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); - - expect(externalService.createIncident).toHaveBeenCalledWith({ - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - description: - 'Incident description (created at 2020-04-27T10:59:46.202Z by Elastic User)', - summary: 'Incident title (created at 2020-04-27T10:59:46.202Z by Elastic User)', - }, - }); - expect(externalService.updateIncident).not.toHaveBeenCalled(); - }); - - test('it calls createIncident correctly without mapping', async () => { - const params = { ...apiParams, externalId: null }; - await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); - - expect(externalService.createIncident).toHaveBeenCalledWith({ - incident: { - description: 'Incident description', - summary: 'Incident title', - issueType: '10006', - labels: ['kibana', 'elastic'], - priority: 'High', - parent: null, - }, - }); - expect(externalService.updateIncident).not.toHaveBeenCalled(); + describe('create incident - cases', () => { + test('it creates an incident', async () => { + const params = { ...apiParams, externalId: null }; + const res = await api.pushToService({ + externalService, + mapping, + params, + logger: mockedLogger, }); - test('it calls createComment correctly', async () => { - const params = { ...apiParams, externalId: null }; - await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); - expect(externalService.createComment).toHaveBeenCalledTimes(2); - expect(externalService.createComment).toHaveBeenNthCalledWith(1, { - incidentId: 'incident-1', - comment: { + expect(res).toEqual({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + comments: [ + { commentId: 'case-comment-1', - comment: 'A comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, + pushedDate: '2020-04-27T10:59:46.202Z', }, - }); - - expect(externalService.createComment).toHaveBeenNthCalledWith(2, { - incidentId: 'incident-1', - comment: { + { commentId: 'case-comment-2', - comment: 'Another comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, + pushedDate: '2020-04-27T10:59:46.202Z', }, - }); + ], }); + }); - test('it calls createComment correctly without mapping', async () => { - const params = { ...apiParams, externalId: null }; - await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); - expect(externalService.createComment).toHaveBeenCalledTimes(2); - expect(externalService.createComment).toHaveBeenNthCalledWith(1, { - incidentId: 'incident-1', - comment: { - commentId: 'case-comment-1', - comment: 'A comment', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - }, - }); + test('it creates an incident without comments', async () => { + const params = { ...apiParams, externalId: null, comments: [] }; + const res = await api.pushToService({ + externalService, + mapping, + params, + logger: mockedLogger, + }); - expect(externalService.createComment).toHaveBeenNthCalledWith(2, { - incidentId: 'incident-1', - comment: { - commentId: 'case-comment-2', - comment: 'Another comment', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - }, - }); + expect(res).toEqual({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', }); }); - describe('update incident', () => { - test('it updates an incident', async () => { - const res = await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-1', - title: 'CK-1', - pushedDate: '2020-04-27T10:59:46.202Z', - url: 'https://siem-kibana.atlassian.net/browse/CK-1', - comments: [ - { - commentId: 'case-comment-1', - pushedDate: '2020-04-27T10:59:46.202Z', - }, - { - commentId: 'case-comment-2', - pushedDate: '2020-04-27T10:59:46.202Z', - }, - ], - }); - }); - - test('it updates an incident without comments', async () => { - const params = { ...apiParams, comments: [] }; - const res = await api.pushToService({ - externalService, - mapping, - params, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-1', - title: 'CK-1', - pushedDate: '2020-04-27T10:59:46.202Z', - url: 'https://siem-kibana.atlassian.net/browse/CK-1', - }); - }); - - test('it calls updateIncident correctly', async () => { - const params = { ...apiParams }; - await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); - - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - description: - 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', - summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + test('it calls createIncident correctly', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); + + expect(externalService.createIncident).toHaveBeenCalledWith({ + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + description: 'Incident description (created at 2020-04-27T10:59:46.202Z by Elastic User)', + summary: 'Incident title (created at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + expect(externalService.updateIncident).not.toHaveBeenCalled(); + }); + + test('it calls createIncident correctly without mapping', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); + + expect(externalService.createIncident).toHaveBeenCalledWith({ + incident: { + description: 'Incident description', + summary: 'Incident title', + issueType: '10006', + labels: ['kibana', 'elastic'], + priority: 'High', + parent: null, + }, + }); + expect(externalService.updateIncident).not.toHaveBeenCalled(); + }); + + test('it calls createComment correctly', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - expect(externalService.createIncident).not.toHaveBeenCalled(); - }); - - test('it calls updateIncident correctly without mapping', async () => { - const params = { ...apiParams }; - await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); - - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - description: 'Incident description', - summary: 'Incident title', - issueType: '10006', - labels: ['kibana', 'elastic'], - priority: 'High', - parent: null, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - expect(externalService.createIncident).not.toHaveBeenCalled(); + }, }); - test('it calls createComment correctly', async () => { - const params = { ...apiParams }; - await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); - expect(externalService.createComment).toHaveBeenCalledTimes(2); - expect(externalService.createComment).toHaveBeenNthCalledWith(1, { - incidentId: 'incident-1', - comment: { - commentId: 'case-comment-1', - comment: 'A comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - - expect(externalService.createComment).toHaveBeenNthCalledWith(2, { - incidentId: 'incident-1', - comment: { - commentId: 'case-comment-2', - comment: 'Another comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); + }, }); + }); - test('it calls createComment correctly without mapping', async () => { - const params = { ...apiParams }; - await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); - expect(externalService.createComment).toHaveBeenCalledTimes(2); - expect(externalService.createComment).toHaveBeenNthCalledWith(1, { - incidentId: 'incident-1', - comment: { - commentId: 'case-comment-1', - comment: 'A comment', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, + test('it calls createComment correctly without mapping', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); + }, + }); - expect(externalService.createComment).toHaveBeenNthCalledWith(2, { - incidentId: 'incident-1', - comment: { - commentId: 'case-comment-2', - comment: 'Another comment', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, }); }); + }); + + describe('update incident', () => { + test('it updates an incident', async () => { + const res = await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); - describe('issueTypes', () => { - test('it returns the issue types correctly', async () => { - const res = await api.issueTypes({ - externalService, - params: {}, - }); - expect(res).toEqual([ + expect(res).toEqual({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + comments: [ { - id: '10006', - name: 'Task', + commentId: 'case-comment-1', + pushedDate: '2020-04-27T10:59:46.202Z', }, { - id: '10007', - name: 'Bug', + commentId: 'case-comment-2', + pushedDate: '2020-04-27T10:59:46.202Z', }, - ]); + ], }); }); - describe('fieldsByIssueType', () => { - test('it returns the fields correctly', async () => { - const res = await api.fieldsByIssueType({ - externalService, - params: { id: '10006' }, - }); - expect(res).toEqual({ - summary: { allowedValues: [], defaultValue: {} }, - priority: { - allowedValues: [ - { - name: 'Medium', - id: '3', - }, - ], - defaultValue: { name: 'Medium', id: '3' }, - }, - }); + test('it updates an incident without comments', async () => { + const params = { ...apiParams, comments: [] }; + const res = await api.pushToService({ + externalService, + mapping, + params, + logger: mockedLogger, + }); + + expect(res).toEqual({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', }); }); - describe('getIssues', () => { - test('it returns the issues correctly', async () => { - const res = await api.issues({ - externalService, - params: { title: 'Title test' }, - }); - expect(res).toEqual([ - { - id: '10267', - key: 'RJ-107', - title: 'Test title', - }, - ]); + test('it calls updateIncident correctly', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); + + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + description: 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, }); + expect(externalService.createIncident).not.toHaveBeenCalled(); }); - describe('getIssue', () => { - test('it returns the issue correctly', async () => { - const res = await api.issue({ - externalService, - params: { id: 'RJ-107' }, - }); - expect(res).toEqual({ - id: '10267', - key: 'RJ-107', - title: 'Test title', - }); + test('it calls updateIncident correctly without mapping', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); + + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + description: 'Incident description', + summary: 'Incident title', + issueType: '10006', + labels: ['kibana', 'elastic'], + priority: 'High', + parent: null, + }, }); + expect(externalService.createIncident).not.toHaveBeenCalled(); }); - describe('mapping variations', () => { - test('overwrite & append', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'append', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', - description: - 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + test('it calls createComment correctly', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('nothing & append', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'nothing', - }); - - mapping.set('description', { - target: 'description', - actionType: 'append', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'nothing', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - description: - 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('append & append', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'append', - }); - - mapping.set('description', { - target: 'description', - actionType: 'append', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'append', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - summary: - 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', - description: - 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', - }, - }); - }); - - test('nothing & nothing', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'nothing', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'nothing', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, + }, + }); + + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('overwrite & nothing', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('overwrite & overwrite', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', - description: - 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('it calls createComment correctly without mapping', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('nothing & overwrite', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'nothing', - }); - - mapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'nothing', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - description: - 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('append & overwrite', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'append', - }); - - mapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'append', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - summary: - 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', - description: - 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('append & nothing', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'append', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'append', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - summary: - 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('comment nothing', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'nothing', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.createComment).not.toHaveBeenCalled(); + }, + }); + }); + }); + + describe('issueTypes', () => { + test('it returns the issue types correctly', async () => { + const res = await api.issueTypes({ + externalService, + params: {}, + }); + expect(res).toEqual([ + { + id: '10006', + name: 'Task', + }, + { + id: '10007', + name: 'Bug', + }, + ]); + }); + }); + + describe('fieldsByIssueType', () => { + test('it returns the fields correctly', async () => { + const res = await api.fieldsByIssueType({ + externalService, + params: { id: '10006' }, + }); + expect(res).toEqual({ + summary: { allowedValues: [], defaultValue: {} }, + priority: { + allowedValues: [ + { + name: 'Medium', + id: '3', + }, + ], + defaultValue: { name: 'Medium', id: '3' }, + }, + }); + }); + }); + + describe('commonFields', () => { + test('it returns the fields correctly', async () => { + const res = await api.commonFields({ + externalService, + params: {}, + }); + expect(res).toEqual(jiraCommonFields); + }); + }); + + describe('getIssues', () => { + test('it returns the issues correctly', async () => { + const res = await api.issues({ + externalService, + params: { title: 'Title test' }, + }); + expect(res).toEqual([ + { + id: '10267', + key: 'RJ-107', + title: 'Test title', + }, + ]); + }); + }); + + describe('getIssue', () => { + test('it returns the issue correctly', async () => { + const res = await api.issue({ + externalService, + params: { id: 'RJ-107' }, + }); + expect(res).toEqual({ + id: '10267', + key: 'RJ-107', + title: 'Test title', + }); + }); + }); + + describe('mapping variations', () => { + test('overwrite & append', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + description: + 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('nothing & append', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + description: + 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('append & append', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + summary: + 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + description: + 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('nothing & nothing', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + }, + }); + }); + + test('overwrite & nothing', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('overwrite & overwrite', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + description: 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('nothing & overwrite', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + description: 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('append & overwrite', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + summary: + 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + description: 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('append & nothing', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + summary: + 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('comment nothing', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'nothing', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, }); + expect(externalService.createComment).not.toHaveBeenCalled(); }); }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts index b98eda799e3aa..9ab89d9ad243c 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts @@ -73,6 +73,7 @@ const createMock = (): jest.Mocked => { key: 'RJ-107', title: 'Test title', })), + getCommonFields: jest.fn().mockImplementation(() => jiraCommonFields), }; service.createComment.mockImplementationOnce(() => @@ -97,7 +98,74 @@ const createMock = (): jest.Mocked => { const externalServiceMock = { create: createMock, }; - +const jiraFields = [ + { + id: 'issuetype', + key: 'issuetype', + name: 'Issue Type', + custom: false, + orderable: true, + navigable: true, + searchable: true, + clauseNames: ['issuetype', 'type'], + schema: { type: 'issuetype', system: 'issuetype' }, + }, + { + id: 'parent', + key: 'parent', + name: 'Parent', + custom: false, + orderable: false, + navigable: true, + searchable: false, + clauseNames: ['parent'], + }, + { + id: 'summary', + key: 'summary', + name: 'Summary', + custom: false, + orderable: true, + navigable: true, + searchable: true, + clauseNames: ['summary'], + schema: { type: 'string', system: 'summary' }, + }, + { + id: 'reporter', + key: 'reporter', + name: 'Reporter', + custom: false, + orderable: true, + navigable: true, + searchable: true, + clauseNames: ['reporter'], + schema: { type: 'user', system: 'reporter' }, + }, + { + id: 'priority', + key: 'priority', + name: 'Priority', + custom: false, + orderable: true, + navigable: true, + searchable: true, + clauseNames: ['priority'], + schema: { type: 'priority', system: 'priority' }, + }, + { + id: 'description', + key: 'description', + name: 'Description', + custom: false, + orderable: true, + navigable: true, + searchable: true, + clauseNames: ['description'], + schema: { type: 'string', system: 'description' }, + }, +]; +const jiraCommonFields = jiraFields.filter(({ id }) => id === 'summary' || id === 'description'); const mapping: Map> = new Map(); mapping.set('title', { @@ -158,4 +226,4 @@ const apiParams: PushToServiceApiParams = { externalObject: { summary: 'Incident title', description: 'Incident description' }, }; -export { externalServiceMock, mapping, executorParams, apiParams }; +export { jiraCommonFields, jiraFields, externalServiceMock, mapping, executorParams, apiParams }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts index fe4e135c76fc3..4035bf1df30c5 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts @@ -11,6 +11,7 @@ import * as utils from '../lib/axios_utils'; import { ExternalService } from './types'; import { Logger } from '../../../../../../src/core/server'; import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; +import { jiraCommonFields, jiraFields } from './mocks'; const logger = loggingSystemMock.create().get() as jest.Mocked; interface ResponseError extends Error { @@ -198,7 +199,7 @@ describe('Jira service', () => { error.response = { data: { errors: { summary: 'Required field' } } }; throw error; }); - expect(service.getIncident('1')).rejects.toThrow( + await expect(service.getIncident('1')).rejects.toThrow( '[Action][Jira]: Unable to get incident with id 1. Error: An error has occurred Reason: Required field' ); }); @@ -348,7 +349,7 @@ describe('Jira service', () => { throw error; }); - expect( + await expect( service.createIncident({ incident: { summary: 'title', @@ -442,7 +443,7 @@ describe('Jira service', () => { throw error; }); - expect( + await expect( service.updateIncident({ incidentId: '1', incident: { @@ -526,7 +527,7 @@ describe('Jira service', () => { throw error; }); - expect( + await expect( service.createComment({ incidentId: '1', comment: { @@ -587,7 +588,7 @@ describe('Jira service', () => { throw error; }); - expect(service.getCapabilities()).rejects.toThrow( + await expect(service.getCapabilities()).rejects.toThrow( '[Action][Jira]: Unable to get capabilities. Error: An error has occurred. Reason: Could not get capabilities' ); }); @@ -657,7 +658,7 @@ describe('Jira service', () => { throw error; }); - expect(service.getIssueTypes()).rejects.toThrow( + await expect(service.getIssueTypes()).rejects.toThrow( '[Action][Jira]: Unable to get issue types. Error: An error has occurred. Reason: Could not get issue types' ); }); @@ -741,7 +742,7 @@ describe('Jira service', () => { throw error; }); - expect(service.getIssueTypes()).rejects.toThrow( + await expect(service.getIssueTypes()).rejects.toThrow( '[Action][Jira]: Unable to get issue types. Error: An error has occurred. Reason: Could not get issue types' ); }); @@ -815,7 +816,7 @@ describe('Jira service', () => { throw error; }); - expect(service.getFieldsByIssueType('10006')).rejects.toThrow( + await expect(service.getFieldsByIssueType('10006')).rejects.toThrow( '[Action][Jira]: Unable to get fields. Error: An error has occurred. Reason: Could not get fields' ); }); @@ -927,7 +928,7 @@ describe('Jira service', () => { throw error; }); - expect(service.getFieldsByIssueType('10006')).rejects.toThrow( + await expect(service.getFieldsByIssueType('10006')).rejects.toThrowError( '[Action][Jira]: Unable to get fields. Error: An error has occurred. Reason: Could not get issue types' ); }); @@ -976,7 +977,7 @@ describe('Jira service', () => { throw error; }); - expect(service.getIssues('Test title')).rejects.toThrow( + await expect(service.getIssues('Test title')).rejects.toThrow( '[Action][Jira]: Unable to get issues. Error: An error has occurred. Reason: Could not get issue types' ); }); @@ -1020,9 +1021,112 @@ describe('Jira service', () => { throw error; }); - expect(service.getIssue('RJ-107')).rejects.toThrow( + await expect(service.getIssue('RJ-107')).rejects.toThrow( '[Action][Jira]: Unable to get issue with id RJ-107. Error: An error has occurred. Reason: Could not get issue types' ); }); }); + + describe('getCommonFields', () => { + const callMocks = () => { + requestMock + .mockImplementationOnce(() => ({ data: jiraFields })) + .mockImplementationOnce(() => ({ + data: { + capabilities: { + 'list-project-issuetypes': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes', + 'list-issuetype-fields': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields', + }, + }, + })) + .mockImplementationOnce(() => ({ + data: { + values: issueTypesResponse.data.projects[0].issuetypes, + }, + })) + .mockImplementationOnce(() => ({ + data: { + capabilities: { + 'list-project-issuetypes': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes', + 'list-issuetype-fields': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields', + }, + }, + })) + .mockImplementationOnce(() => ({ + data: { + capabilities: { + 'list-project-issuetypes': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes', + 'list-issuetype-fields': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields', + }, + }, + })) + .mockImplementationOnce(() => ({ + data: { + values: [ + { fieldId: 'summary' }, + { fieldId: 'description' }, + { + fieldId: 'priority', + allowedValues: [ + { + name: 'Medium', + id: '3', + }, + ], + defaultValue: { + name: 'Medium', + id: '3', + }, + }, + ], + }, + })) + .mockImplementationOnce(() => ({ + data: { + values: [{ fieldId: 'summary' }, { fieldId: 'description' }], + }, + })); + }; + beforeEach(() => { + jest.resetAllMocks(); + }); + test('it should call request with correct arguments', async () => { + callMocks(); + await service.getCommonFields(); + const callUrls = [ + 'https://siem-kibana.atlassian.net/rest/api/2/field', + 'https://siem-kibana.atlassian.net/rest/capabilities', + 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes', + 'https://siem-kibana.atlassian.net/rest/capabilities', + 'https://siem-kibana.atlassian.net/rest/capabilities', + 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes/10006', + 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes/10007', + ]; + requestMock.mock.calls.forEach((call, i) => { + expect(call[0].url).toEqual(callUrls[i]); + }); + }); + test('it returns common fields correctly', async () => { + callMocks(); + const res = await service.getCommonFields(); + expect(res).toEqual(jiraCommonFields); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + const error: ResponseError = new Error('An error has occurred'); + error.response = { data: { errors: { summary: 'Required field' } } }; + throw error; + }); + await expect(service.getCommonFields()).rejects.toThrow( + '[Action][Jira]: Unable to get fields. Error: An error has occurred Reason: Required field' + ); + }); + }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts index f0dfac6ab1064..08b0b356b5976 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts @@ -166,7 +166,7 @@ export const createExternalService = ( throw new Error( getErrorMessage( i18n.NAME, - `Unable to get fields from Jira. Error: ${error.message} Reason: ${createErrorMessage( + `Unable to get fields. Error: ${error.message} Reason: ${createErrorMessage( error.response?.data )}` ) @@ -389,7 +389,6 @@ export const createExternalService = ( const getFieldsByIssueType = async (issueTypeId: string) => { const capabilitiesResponse = await getCapabilities(); const supportsNewAPI = hasSupportForNewAPI(capabilitiesResponse); - try { if (!supportsNewAPI) { const res = await request({ @@ -433,19 +432,22 @@ export const createExternalService = ( }; const getCommonFields = async () => { - const fields = await getFields(); - const issueTypes = await getIssueTypes(); - const fieldTypes = await Promise.all( - issueTypes.map((issueType) => getFieldsByIssueType(issueType.id)) - ); - const commonFields = fieldTypes.reduce((acc: string[], fieldTypesByIssue) => { - const newKeys = Object.keys(fieldTypesByIssue); - if (acc.length === 0) { - return [...newKeys]; - } - return acc.reduce((add: string[], key) => (newKeys.includes(key) ? [...add, key] : add), []); - }, []); - return fields.filter((f) => commonFields.includes(f.id)); + try { + const [fields, issueTypes] = await Promise.all([getFields(), getIssueTypes()]); + const fieldTypes = await Promise.all( + issueTypes.map((issueType) => getFieldsByIssueType(issueType.id)) + ); + const commonFields = fieldTypes.reduce((acc: string[], fieldTypesByIssue) => { + const newKeys = Object.keys(fieldTypesByIssue); + return acc.length === 0 + ? [...newKeys] + : acc.reduce((add: string[], key) => (newKeys.includes(key) ? [...add, key] : add), []); + }, []); + return fields.filter((f) => commonFields.includes(f.id)); + } catch (error) { + // errors that happen here would be thrown in the contained async calls + throw error; + } }; const getIssues = async (title: string) => { diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/mocks.ts index 2e841728159a3..51f58077044c8 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/mocks.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/mocks.ts @@ -8,8 +8,275 @@ import { ExternalService, PushToServiceApiParams, ExecutorSubActionPushParams } import { MapRecord } from '../case/types'; +export const resilientFields = [ + { + id: 17, + name: 'name', + text: 'Name', + prefix: null, + type_id: 0, + tooltip: 'A unique name to identify this particular incident.', + input_type: 'text', + required: 'always', + hide_notification: false, + chosen: false, + default_chosen_by_server: false, + blank_option: false, + internal: true, + uuid: 'ad6ed4f2-8d87-4ba2-81fa-03568a9326cc', + operations: [ + 'equals', + 'not_equals', + 'contains', + 'not_contains', + 'changed', + 'changed_to', + 'not_changed_to', + 'has_a_value', + 'not_has_a_value', + ], + operation_perms: { + changed_to: { + show_in_manual_actions: false, + show_in_auto_actions: true, + show_in_notifications: true, + }, + has_a_value: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_changed_to: { + show_in_manual_actions: false, + show_in_auto_actions: true, + show_in_notifications: true, + }, + equals: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + changed: { + show_in_manual_actions: false, + show_in_auto_actions: true, + show_in_notifications: true, + }, + contains: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_contains: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_equals: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_has_a_value: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + }, + values: [], + perms: { + delete: false, + modify_name: false, + modify_values: false, + modify_blank: false, + modify_required: false, + modify_operations: false, + modify_chosen: false, + modify_default: false, + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + show_in_scripts: true, + modify_type: ['text'], + sort: true, + }, + read_only: false, + changeable: true, + rich_text: false, + templates: [], + deprecated: false, + tags: [], + calculated: false, + is_tracked: false, + allow_default_value: false, + }, + { + id: 15, + name: 'description', + text: 'Description', + prefix: null, + type_id: 0, + tooltip: 'A free form text description of the incident.', + input_type: 'textarea', + hide_notification: false, + chosen: false, + default_chosen_by_server: false, + blank_option: false, + internal: true, + uuid: '420d70b1-98f9-4681-a20b-84f36a9e5e48', + operations: [ + 'equals', + 'not_equals', + 'contains', + 'not_contains', + 'changed', + 'changed_to', + 'not_changed_to', + 'has_a_value', + 'not_has_a_value', + ], + operation_perms: { + changed_to: { + show_in_manual_actions: false, + show_in_auto_actions: true, + show_in_notifications: true, + }, + has_a_value: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_changed_to: { + show_in_manual_actions: false, + show_in_auto_actions: true, + show_in_notifications: true, + }, + equals: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + changed: { + show_in_manual_actions: false, + show_in_auto_actions: true, + show_in_notifications: true, + }, + contains: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_contains: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_equals: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_has_a_value: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + }, + values: [], + perms: { + delete: false, + modify_name: false, + modify_values: false, + modify_blank: false, + modify_required: false, + modify_operations: false, + modify_chosen: false, + modify_default: false, + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + show_in_scripts: true, + modify_type: ['textarea'], + sort: true, + }, + read_only: false, + changeable: true, + rich_text: true, + templates: [], + deprecated: false, + tags: [], + calculated: false, + is_tracked: false, + allow_default_value: false, + }, + { + id: 65, + name: 'create_date', + text: 'Date Created', + prefix: null, + type_id: 0, + tooltip: 'The date the incident was created. This field is read-only.', + input_type: 'datetimepicker', + hide_notification: false, + chosen: false, + default_chosen_by_server: false, + blank_option: false, + internal: true, + uuid: 'b4faf728-881a-4e8b-bf0b-d39b720392a1', + operations: ['due_within', 'overdue_by', 'has_a_value', 'not_has_a_value'], + operation_perms: { + has_a_value: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_has_a_value: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + due_within: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + overdue_by: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + }, + values: [], + perms: { + delete: false, + modify_name: false, + modify_values: false, + modify_blank: false, + modify_required: false, + modify_operations: false, + modify_chosen: false, + modify_default: false, + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + show_in_scripts: true, + modify_type: ['datetimepicker'], + sort: true, + }, + read_only: true, + changeable: false, + rich_text: false, + templates: [], + deprecated: false, + tags: [], + calculated: false, + is_tracked: false, + allow_default_value: false, + }, +]; + const createMock = (): jest.Mocked => { const service = { + getCommonFields: jest.fn().mockImplementation(() => Promise.resolve(resilientFields)), getIncident: jest.fn().mockImplementation(() => Promise.resolve({ id: '1', diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.test.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.test.ts index 86ea352625a5b..19c67e4695b5a 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.test.ts @@ -11,7 +11,7 @@ import * as utils from '../lib/axios_utils'; import { ExternalService } from './types'; import { Logger } from '../../../../../../src/core/server'; import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; -import { incidentTypes, severity } from './mocks'; +import { incidentTypes, resilientFields, severity } from './mocks'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -231,7 +231,7 @@ describe('IBM Resilient service', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - expect(service.getIncident('1')).rejects.toThrow( + await expect(service.getIncident('1')).rejects.toThrow( 'Unable to get incident with id 1. Error: An error has occurred' ); }); @@ -310,7 +310,7 @@ describe('IBM Resilient service', () => { throw new Error('An error has occurred'); }); - expect( + await expect( service.createIncident({ incident: { name: 'title', @@ -418,7 +418,7 @@ describe('IBM Resilient service', () => { test('it should throw an error', async () => { mockIncidentUpdate(true); - expect( + await expect( service.updateIncident({ incidentId: '1', incident: { @@ -502,7 +502,7 @@ describe('IBM Resilient service', () => { throw new Error('An error has occurred'); }); - expect( + await expect( service.createComment({ incidentId: '1', comment: { @@ -541,7 +541,7 @@ describe('IBM Resilient service', () => { throw new Error('An error has occurred'); }); - expect(service.getIncidentTypes()).rejects.toThrow( + await expect(service.getIncidentTypes()).rejects.toThrow( '[Action][IBM Resilient]: Unable to get incident types. Error: An error has occurred.' ); }); @@ -578,9 +578,40 @@ describe('IBM Resilient service', () => { throw new Error('An error has occurred'); }); - expect(service.getIncidentTypes()).rejects.toThrow( + await expect(service.getIncidentTypes()).rejects.toThrow( '[Action][IBM Resilient]: Unable to get incident types. Error: An error has occurred.' ); }); }); + + describe('getCommonFields', () => { + test('it should call request with correct arguments', async () => { + requestMock.mockImplementation(() => ({ + data: resilientFields, + })); + await service.getCommonFields(); + + expect(requestMock).toHaveBeenCalledWith({ + axios, + logger, + url: 'https://resilient.elastic.co/rest/orgs/201/types/incident/fields', + }); + }); + test('it returns common fields correctly', async () => { + requestMock.mockImplementation(() => ({ + data: resilientFields, + })); + const res = await service.getCommonFields(); + expect(res).toEqual(resilientFields); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + throw new Error('An error has occurred'); + }); + await expect(service.getCommonFields()).rejects.toThrow( + 'Unable to get fields. Error: An error has occurred' + ); + }); + }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts index f0ae7868daf94..be4ebf9cb662e 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts @@ -307,7 +307,6 @@ export const createExternalService = ( try { const res = await request({ axios: axiosInstance, - method: 'get', url: incidentFieldsUrl, logger, proxySettings, diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts index d49c2f265d04f..cef837de74229 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts @@ -5,7 +5,7 @@ */ import { Logger } from '../../../../../../src/core/server'; -import { externalServiceMock, mapping, apiParams } from './mocks'; +import { externalServiceMock, mapping, apiParams, serviceNowCommonFields } from './mocks'; import { ExternalService } from './types'; import { api } from './api'; let mockedLogger: jest.Mocked; @@ -15,634 +15,619 @@ describe('api', () => { beforeEach(() => { externalService = externalServiceMock.create(); - jest.clearAllMocks(); }); - afterEach(() => { - jest.clearAllMocks(); - }); + describe('create incident', () => { + test('it creates an incident', async () => { + const params = { ...apiParams, externalId: null }; + const res = await api.pushToService({ + externalService, + mapping, + params, + secrets: {}, + logger: mockedLogger, + }); - describe('pushToService', () => { - describe('create incident', () => { - test('it creates an incident', async () => { - const params = { ...apiParams, externalId: null }; - const res = await api.pushToService({ - externalService, - mapping, - params, - secrets: {}, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-1', - title: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - comments: [ - { - commentId: 'case-comment-1', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - { - commentId: 'case-comment-2', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - ], - }); - }); - - test('it creates an incident without comments', async () => { - const params = { ...apiParams, externalId: null, comments: [] }; - const res = await api.pushToService({ - externalService, - mapping, - params, - secrets: {}, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-1', - title: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('it calls createIncident correctly', async () => { - const params = { ...apiParams, externalId: null, comments: [] }; - await api.pushToService({ - externalService, - mapping, - params, - secrets: { username: 'elastic', password: 'elastic' }, - logger: mockedLogger, - }); - - expect(externalService.createIncident).toHaveBeenCalledWith({ - incident: { - severity: '1', - urgency: '2', - impact: '3', - caller_id: 'elastic', - description: - 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: - 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - expect(externalService.updateIncident).not.toHaveBeenCalled(); - }); - - test('it calls updateIncident correctly when creating an incident and having comments', async () => { - const params = { ...apiParams, externalId: null }; - await api.pushToService({ - externalService, - mapping, - params, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledTimes(2); - expect(externalService.updateIncident).toHaveBeenNthCalledWith(1, { - incident: { - severity: '1', - urgency: '2', - impact: '3', - comments: 'A comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: - 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + expect(res).toEqual({ + id: 'incident-1', + title: 'INC01', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + comments: [ + { + commentId: 'case-comment-1', + pushedDate: '2020-03-10T12:24:20.000Z', }, - incidentId: 'incident-1', - }); - - expect(externalService.updateIncident).toHaveBeenNthCalledWith(2, { - incident: { - severity: '1', - urgency: '2', - impact: '3', - comments: 'Another comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: - 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + { + commentId: 'case-comment-2', + pushedDate: '2020-03-10T12:24:20.000Z', }, - incidentId: 'incident-1', - }); + ], }); }); - describe('update incident', () => { - test('it updates an incident', async () => { - const res = await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-2', - title: 'INC02', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - comments: [ - { - commentId: 'case-comment-1', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - { - commentId: 'case-comment-2', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - ], - }); - }); - - test('it updates an incident without comments', async () => { - const params = { ...apiParams, comments: [] }; - const res = await api.pushToService({ - externalService, - mapping, - params, - secrets: {}, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-2', - title: 'INC02', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('it calls updateIncident correctly', async () => { - const params = { ...apiParams }; - await api.pushToService({ - externalService, - mapping, - params, - secrets: {}, - logger: mockedLogger, - }); - - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - description: - 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: - 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - expect(externalService.createIncident).not.toHaveBeenCalled(); - }); - - test('it calls updateIncident to create a comments correctly', async () => { - const params = { ...apiParams }; - await api.pushToService({ - externalService, - mapping, - params, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledTimes(3); - expect(externalService.updateIncident).toHaveBeenNthCalledWith(1, { - incident: { - severity: '1', - urgency: '2', - impact: '3', - description: - 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: - 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - incidentId: 'incident-3', - }); - - expect(externalService.updateIncident).toHaveBeenNthCalledWith(2, { - incident: { - severity: '1', - urgency: '2', - impact: '3', - comments: 'A comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: - 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - incidentId: 'incident-2', - }); + test('it creates an incident without comments', async () => { + const params = { ...apiParams, externalId: null, comments: [] }; + const res = await api.pushToService({ + externalService, + mapping, + params, + secrets: {}, + logger: mockedLogger, + }); + + expect(res).toEqual({ + id: 'incident-1', + title: 'INC01', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', }); }); - describe('mapping variations', () => { - test('overwrite & append', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'append', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - short_description: - 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - }); - - test('nothing & append', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'nothing', - }); - - mapping.set('description', { - target: 'description', - actionType: 'append', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'nothing', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - description: - 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - }); - - test('append & append', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'append', - }); - - mapping.set('description', { - target: 'description', - actionType: 'append', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'append', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - short_description: - 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - }); - - test('nothing & nothing', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'nothing', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'nothing', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - }, - }); - }); - - test('overwrite & nothing', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - short_description: - 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - }); - - test('overwrite & overwrite', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - short_description: - 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - }); - - test('nothing & overwrite', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'nothing', - }); - - mapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'nothing', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - description: - 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - }); - - test('append & overwrite', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'append', - }); - - mapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'append', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - short_description: - 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + test('it calls createIncident correctly', async () => { + const params = { ...apiParams, externalId: null, comments: [] }; + await api.pushToService({ + externalService, + mapping, + params, + secrets: { username: 'elastic', password: 'elastic' }, + logger: mockedLogger, + }); + + expect(externalService.createIncident).toHaveBeenCalledWith({ + incident: { + severity: '1', + urgency: '2', + impact: '3', + caller_id: 'elastic', + description: 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + expect(externalService.updateIncident).not.toHaveBeenCalled(); + }); + + test('it calls updateIncident correctly when creating an incident and having comments', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ + externalService, + mapping, + params, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledTimes(2); + expect(externalService.updateIncident).toHaveBeenNthCalledWith(1, { + incident: { + severity: '1', + urgency: '2', + impact: '3', + comments: 'A comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', + description: 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + incidentId: 'incident-1', + }); + + expect(externalService.updateIncident).toHaveBeenNthCalledWith(2, { + incident: { + severity: '1', + urgency: '2', + impact: '3', + comments: 'Another comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', + description: 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + incidentId: 'incident-1', + }); + }); + }); + + describe('update incident', () => { + test('it updates an incident', async () => { + const res = await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + + expect(res).toEqual({ + id: 'incident-2', + title: 'INC02', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + comments: [ + { + commentId: 'case-comment-1', + pushedDate: '2020-03-10T12:24:20.000Z', }, - }); - }); - - test('append & nothing', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'append', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'append', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - short_description: - 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + { + commentId: 'case-comment-2', + pushedDate: '2020-03-10T12:24:20.000Z', }, - }); - }); - - test('comment nothing', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'nothing', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledTimes(1); + ], + }); + }); + + test('it updates an incident without comments', async () => { + const params = { ...apiParams, comments: [] }; + const res = await api.pushToService({ + externalService, + mapping, + params, + secrets: {}, + logger: mockedLogger, + }); + + expect(res).toEqual({ + id: 'incident-2', + title: 'INC02', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + }); + }); + + test('it calls updateIncident correctly', async () => { + const params = { ...apiParams }; + await api.pushToService({ + externalService, + mapping, + params, + secrets: {}, + logger: mockedLogger, + }); + + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + expect(externalService.createIncident).not.toHaveBeenCalled(); + }); + + test('it calls updateIncident to create a comments correctly', async () => { + const params = { ...apiParams }; + await api.pushToService({ + externalService, + mapping, + params, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledTimes(3); + expect(externalService.updateIncident).toHaveBeenNthCalledWith(1, { + incident: { + severity: '1', + urgency: '2', + impact: '3', + description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + incidentId: 'incident-3', + }); + + expect(externalService.updateIncident).toHaveBeenNthCalledWith(2, { + incident: { + severity: '1', + urgency: '2', + impact: '3', + comments: 'A comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', + description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + incidentId: 'incident-2', + }); + }); + }); + + describe('mapping variations', () => { + test('overwrite & append', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + short_description: 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + description: + 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('nothing & append', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + description: + 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('append & append', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + short_description: + 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + description: + 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('nothing & nothing', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + }, + }); + }); + + test('overwrite & nothing', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + short_description: 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('overwrite & overwrite', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + short_description: 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('nothing & overwrite', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('append & overwrite', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + short_description: + 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('append & nothing', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + short_description: + 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('comment nothing', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'nothing', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledTimes(1); + }); + }); + + describe('commonFields', () => { + test('it returns the fields correctly', async () => { + const res = await api.commonFields({ + externalService, + params: {}, }); + expect(res).toEqual(serviceNowCommonFields); }); }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts index 7c2b1bd9d73c1..f82028fa47e98 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts @@ -7,8 +7,36 @@ import { ExternalService, PushToServiceApiParams, ExecutorSubActionPushParams } from './types'; import { MapRecord } from '../case/types'; +export const serviceNowCommonFields = [ + { + column_label: 'Close notes', + max_length: '4000', + element: 'close_notes', + }, + { + column_label: 'Description', + max_length: '4000', + element: 'description', + }, + { + column_label: 'Short description', + max_length: '160', + element: 'short_description', + }, + { + column_label: 'Created by', + max_length: '40', + element: 'sys_created_by', + }, + { + column_label: 'Updated by', + max_length: '40', + element: 'sys_updated_by', + }, +]; const createMock = (): jest.Mocked => { const service = { + getCommonFields: jest.fn().mockImplementation(() => Promise.resolve(serviceNowCommonFields)), getIncident: jest.fn().mockImplementation(() => Promise.resolve({ short_description: 'title from servicenow', diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts index 2adcdf561ce17..d21c51246fe8c 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts @@ -11,6 +11,7 @@ import * as utils from '../lib/axios_utils'; import { ExternalService } from './types'; import { Logger } from '../../../../../../src/core/server'; import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; +import { serviceNowCommonFields } from './mocks'; const logger = loggingSystemMock.create().get() as jest.Mocked; jest.mock('axios'); @@ -108,7 +109,7 @@ describe('ServiceNow service', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - expect(service.getIncident('1')).rejects.toThrow( + await expect(service.getIncident('1')).rejects.toThrow( 'Unable to get incident with id 1. Error: An error has occurred' ); }); @@ -155,7 +156,7 @@ describe('ServiceNow service', () => { throw new Error('An error has occurred'); }); - expect( + await expect( service.createIncident({ incident: { short_description: 'title', description: 'desc' }, }) @@ -207,7 +208,7 @@ describe('ServiceNow service', () => { throw new Error('An error has occurred'); }); - expect( + await expect( service.updateIncident({ incidentId: '1', incident: { short_description: 'title', description: 'desc' }, @@ -234,4 +235,36 @@ describe('ServiceNow service', () => { }); }); }); + + describe('getCommonFields', () => { + test('it should call request with correct arguments', async () => { + requestMock.mockImplementation(() => ({ + data: { result: serviceNowCommonFields }, + })); + await service.getCommonFields(); + + expect(requestMock).toHaveBeenCalledWith({ + axios, + logger, + url: + 'https://dev102283.service-now.com/api/now/v2/table/sys_dictionary?sysparm_query=name=task^internal_type=string&active=true&read_only=false&sysparm_fields=max_length,element,column_label', + }); + }); + test('it returns common fields correctly', async () => { + requestMock.mockImplementation(() => ({ + data: { result: serviceNowCommonFields }, + })); + const res = await service.getCommonFields(); + expect(res).toEqual(serviceNowCommonFields); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + throw new Error('An error has occurred'); + }); + await expect(service.getCommonFields()).rejects.toThrow( + 'Unable to get common fields. Error: An error has occurred' + ); + }); + }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts index ebef85ddb3357..5855f906c839e 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts @@ -135,13 +135,12 @@ export const createExternalService = ( url: fieldsUrl, logger, proxySettings, - method: 'get', }); return res.data.result.length > 0 ? res.data.result : []; } catch (error) { throw new Error( - getErrorMessage(i18n.NAME, `Unable to get incident fields. Error: ${error.message}`) + getErrorMessage(i18n.NAME, `Unable to get common fields. Error: ${error.message}`) ); } }; From 0be520d16c93b33e52b8cefbde63537f4d97abeb Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Tue, 3 Nov 2020 15:10:17 -0700 Subject: [PATCH 08/13] update docs --- x-pack/plugins/actions/README.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md index 02e8e91c987d8..19f9f33a0ffd0 100644 --- a/x-pack/plugins/actions/README.md +++ b/x-pack/plugins/actions/README.md @@ -75,6 +75,7 @@ Table of Contents - [`params`](#params-7) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-1) - [`subActionParams (issueTypes)`](#subactionparams-issuetypes) + - [`subActionParams (commonFields)`](#subactionparams-jira-fields) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2) - [IBM Resilient](#ibm-resilient) - [`config`](#config-8) @@ -563,7 +564,7 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a | Property | Description | Type | | --------------- | ------------------------------------------------------------------------------------ | ------ | -| subAction | The sub action to perform. It can be `pushToService`, `handshake`, and `getIncident` | string | +| subAction | The sub action to perform. It can be `commonFields`, `pushToService`, `handshake`, and `getIncident` | string | | subActionParams | The parameters of the sub action | object | #### `subActionParams (pushToService)` @@ -580,6 +581,10 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a | urgency | The name of the urgency in ServiceNow. | string _(optional)_ | | impact | The name of the impact in ServiceNow. | string _(optional)_ | +#### `subActionParams (commonFields)` + +No parameters for `commonFields` sub-action. Provide an empty object `{}`. + --- ## Jira @@ -606,7 +611,7 @@ The Jira action uses the [V2 API](https://developer.atlassian.com/cloud/jira/pla | Property | Description | Type | | --------------- | ----------------------------------------------------------------------------------------------------------------------- | ------ | -| subAction | The sub action to perform. It can be `pushToService`, `handshake`, `getIncident`, `issueTypes`, and `fieldsByIssueType` | string | +| subAction | The sub action to perform. It can be `commonFields`, `pushToService`, `handshake`, `getIncident`, `issueTypes`, and `fieldsByIssueType` | string | | subActionParams | The parameters of the sub action | object | #### `subActionParams (pushToService)` @@ -627,6 +632,10 @@ The Jira action uses the [V2 API](https://developer.atlassian.com/cloud/jira/pla No parameters for `issueTypes` sub-action. Provide an empty object `{}`. +#### `subActionParams (commonFields)` + +No parameters for `commonFields` sub-action. Provide an empty object `{}`. + #### `subActionParams (pushToService)` | Property | Description | Type | @@ -655,7 +664,7 @@ ID: `.resilient` | Property | Description | Type | | --------------- | ------------------------------------------------------------------------------------ | ------ | -| subAction | The sub action to perform. It can be `pushToService`, `handshake`, and `getIncident` | string | +| subAction | The sub action to perform. It can be `commonFields`, `pushToService`, `handshake`, and `getIncident` | string | | subActionParams | The parameters of the sub action | object | #### `subActionParams (pushToService)` @@ -670,6 +679,10 @@ ID: `.resilient` | incidentTypes | An array with the ids of IBM Resilient incident types. | number[] _(optional)_ | | severityCode | IBM Resilient id of the severity code. | number _(optional)_ | +#### `subActionParams (commonFields)` + +No parameters for `commonFields` sub-action. Provide an empty object `{}`. + # Command Line Utility The [`kbn-action`](https://github.com/pmuellr/kbn-action) tool can be used to send HTTP requests to the Actions plugin. For instance, to create a Slack action from the `.slack` Action Type, use the following command: From 054340ea366e4dd80abf92a8f39310f8d99d5611 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Tue, 3 Nov 2020 15:13:16 -0700 Subject: [PATCH 09/13] update docs --- x-pack/plugins/actions/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md index 19f9f33a0ffd0..6883883e5ec53 100644 --- a/x-pack/plugins/actions/README.md +++ b/x-pack/plugins/actions/README.md @@ -69,19 +69,21 @@ Table of Contents - [`secrets`](#secrets-6) - [`params`](#params-6) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice) + - [`subActionParams (commonFields)`](#subactionparams-commonfields-1) - [Jira](#jira) - [`config`](#config-7) - [`secrets`](#secrets-7) - [`params`](#params-7) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-1) - [`subActionParams (issueTypes)`](#subactionparams-issuetypes) - - [`subActionParams (commonFields)`](#subactionparams-jira-fields) + - [`subActionParams (commonFields)`](#subactionparams-commonfields-2) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2) - [IBM Resilient](#ibm-resilient) - [`config`](#config-8) - [`secrets`](#secrets-8) - [`params`](#params-8) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-3) + - [`subActionParams (commonFields)`](#subactionparams-commonfields-3) - [Command Line Utility](#command-line-utility) - [Developing New Action Types](#developing-new-action-types) - [licensing](#licensing) From 40717201f0926236ddce756eee967a59d3b13f22 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Wed, 4 Nov 2020 08:25:08 -0700 Subject: [PATCH 10/13] fixes api tests --- .../tests/actions/builtin_action_types/jira.ts | 10 +++++----- .../tests/actions/builtin_action_types/resilient.ts | 10 +++++----- .../tests/actions/builtin_action_types/servicenow.ts | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts index 39f64dd037945..9de0f53bd7265 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts @@ -333,7 +333,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subAction]: expected value to equal [pushToService]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]\n- [5.subAction]: expected value to equal [issues]\n- [6.subAction]: expected value to equal [issue]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', }); }); }); @@ -351,7 +351,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]\n- [5.subAction]: expected value to equal [issues]\n- [6.subAction]: expected value to equal [issue]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', }); }); }); @@ -374,7 +374,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]\n- [5.subAction]: expected value to equal [issues]\n- [6.subAction]: expected value to equal [issue]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', }); }); }); @@ -402,7 +402,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]\n- [5.subAction]: expected value to equal [issues]\n- [6.subAction]: expected value to equal [issue]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', }); }); }); @@ -430,7 +430,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]\n- [5.subAction]: expected value to equal [issues]\n- [6.subAction]: expected value to equal [issue]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/resilient.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/resilient.ts index 5d54ea99889c1..7e862c2499173 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/resilient.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/resilient.ts @@ -334,7 +334,7 @@ export default function resilientTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subAction]: expected value to equal [pushToService]\n- [3.subAction]: expected value to equal [incidentTypes]\n- [4.subAction]: expected value to equal [severity]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', }); }); }); @@ -352,7 +352,7 @@ export default function resilientTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]\n- [3.subAction]: expected value to equal [incidentTypes]\n- [4.subAction]: expected value to equal [severity]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', }); }); }); @@ -375,7 +375,7 @@ export default function resilientTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]\n- [3.subAction]: expected value to equal [incidentTypes]\n- [4.subAction]: expected value to equal [severity]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', }); }); }); @@ -403,7 +403,7 @@ export default function resilientTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [3.subAction]: expected value to equal [incidentTypes]\n- [4.subAction]: expected value to equal [severity]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', }); }); }); @@ -431,7 +431,7 @@ export default function resilientTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [3.subAction]: expected value to equal [incidentTypes]\n- [4.subAction]: expected value to equal [severity]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts index 0684707c73824..1347b4d078b0a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts @@ -328,7 +328,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subAction]: expected value to equal [pushToService]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]', }); }); }); @@ -346,7 +346,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]', }); }); }); @@ -369,7 +369,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]', }); }); }); @@ -397,7 +397,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments.0.commentId]: expected value of type [string] but got [undefined]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments.0.commentId]: expected value of type [string] but got [undefined]', }); }); }); @@ -425,7 +425,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments.0.comment]: expected value of type [string] but got [undefined]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments.0.comment]: expected value of type [string] but got [undefined]', }); }); }); From a4bc0318990ef59de23624abfe3d2cdede8d44d8 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Wed, 4 Nov 2020 12:09:41 -0700 Subject: [PATCH 11/13] rm comments --- x-pack/plugins/actions/server/builtin_action_types/jira/api.ts | 1 - x-pack/plugins/actions/server/builtin_action_types/jira/index.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts index 97e5080bfa882..b194dce7cd466 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts @@ -89,7 +89,6 @@ const pushToServiceHandler = async ({ } let incident: Incident; - // TO DO STEPH // TODO: should be removed later but currently keep it for the Case implementation support if (mapping) { const fields = prepareFieldsForTransformation({ diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts index 4fae1874f2ac1..6ea8028f1b08f 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts @@ -114,7 +114,6 @@ async function executor( const { comments, externalId, ...restParams } = pushToServiceParams; const incidentConfiguration = config.incidentConfiguration; - // TO DO STEPH const mapping = incidentConfiguration ? buildMap(incidentConfiguration.mapping) : null; const externalObject = config.incidentConfiguration && mapping From 6a19a041972b12c94f6441b77a13b9a42c389506 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Thu, 5 Nov 2020 12:06:59 -0700 Subject: [PATCH 12/13] jira refactor, rename from commonFields to getFields --- x-pack/plugins/actions/README.md | 24 +++---- .../builtin_action_types/jira/api.test.ts | 12 +--- .../server/builtin_action_types/jira/api.ts | 6 +- .../server/builtin_action_types/jira/index.ts | 6 +- .../server/builtin_action_types/jira/mocks.ts | 72 +------------------ .../builtin_action_types/jira/schema.ts | 2 +- .../builtin_action_types/jira/service.test.ts | 69 +++++++++++++----- .../builtin_action_types/jira/service.ts | 63 ++++++++-------- .../server/builtin_action_types/jira/types.ts | 13 ++-- .../builtin_action_types/resilient/api.ts | 6 +- .../builtin_action_types/resilient/index.ts | 15 ++-- .../builtin_action_types/resilient/mocks.ts | 2 +- .../builtin_action_types/resilient/schema.ts | 2 +- .../resilient/service.test.ts | 8 +-- .../builtin_action_types/resilient/service.ts | 4 +- .../builtin_action_types/resilient/types.ts | 4 +- .../servicenow/api.test.ts | 4 +- .../builtin_action_types/servicenow/api.ts | 6 +- .../builtin_action_types/servicenow/index.ts | 10 +-- .../builtin_action_types/servicenow/mocks.ts | 2 +- .../builtin_action_types/servicenow/schema.ts | 4 +- .../servicenow/service.test.ts | 8 +-- .../servicenow/service.ts | 4 +- .../builtin_action_types/servicenow/types.ts | 4 +- .../actions/builtin_action_types/jira.ts | 10 +-- .../actions/builtin_action_types/resilient.ts | 10 +-- .../builtin_action_types/servicenow.ts | 10 +-- 27 files changed, 165 insertions(+), 215 deletions(-) diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md index 6883883e5ec53..7d7e48dfc579b 100644 --- a/x-pack/plugins/actions/README.md +++ b/x-pack/plugins/actions/README.md @@ -69,21 +69,21 @@ Table of Contents - [`secrets`](#secrets-6) - [`params`](#params-6) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice) - - [`subActionParams (commonFields)`](#subactionparams-commonfields-1) + - [`subActionParams (getFields)`](#subactionparams-getfields-1) - [Jira](#jira) - [`config`](#config-7) - [`secrets`](#secrets-7) - [`params`](#params-7) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-1) - [`subActionParams (issueTypes)`](#subactionparams-issuetypes) - - [`subActionParams (commonFields)`](#subactionparams-commonfields-2) + - [`subActionParams (getFields)`](#subactionparams-getfields-2) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2) - [IBM Resilient](#ibm-resilient) - [`config`](#config-8) - [`secrets`](#secrets-8) - [`params`](#params-8) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-3) - - [`subActionParams (commonFields)`](#subactionparams-commonfields-3) + - [`subActionParams (getFields)`](#subactionparams-getfields-3) - [Command Line Utility](#command-line-utility) - [Developing New Action Types](#developing-new-action-types) - [licensing](#licensing) @@ -566,7 +566,7 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a | Property | Description | Type | | --------------- | ------------------------------------------------------------------------------------ | ------ | -| subAction | The sub action to perform. It can be `commonFields`, `pushToService`, `handshake`, and `getIncident` | string | +| subAction | The sub action to perform. It can be `getFields`, `pushToService`, `handshake`, and `getIncident` | string | | subActionParams | The parameters of the sub action | object | #### `subActionParams (pushToService)` @@ -583,9 +583,9 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a | urgency | The name of the urgency in ServiceNow. | string _(optional)_ | | impact | The name of the impact in ServiceNow. | string _(optional)_ | -#### `subActionParams (commonFields)` +#### `subActionParams (getFields)` -No parameters for `commonFields` sub-action. Provide an empty object `{}`. +No parameters for `getFields` sub-action. Provide an empty object `{}`. --- @@ -613,7 +613,7 @@ The Jira action uses the [V2 API](https://developer.atlassian.com/cloud/jira/pla | Property | Description | Type | | --------------- | ----------------------------------------------------------------------------------------------------------------------- | ------ | -| subAction | The sub action to perform. It can be `commonFields`, `pushToService`, `handshake`, `getIncident`, `issueTypes`, and `fieldsByIssueType` | string | +| subAction | The sub action to perform. It can be `getFields`, `pushToService`, `handshake`, `getIncident`, `issueTypes`, and `fieldsByIssueType` | string | | subActionParams | The parameters of the sub action | object | #### `subActionParams (pushToService)` @@ -634,9 +634,9 @@ The Jira action uses the [V2 API](https://developer.atlassian.com/cloud/jira/pla No parameters for `issueTypes` sub-action. Provide an empty object `{}`. -#### `subActionParams (commonFields)` +#### `subActionParams (getFields)` -No parameters for `commonFields` sub-action. Provide an empty object `{}`. +No parameters for `getFields` sub-action. Provide an empty object `{}`. #### `subActionParams (pushToService)` @@ -666,7 +666,7 @@ ID: `.resilient` | Property | Description | Type | | --------------- | ------------------------------------------------------------------------------------ | ------ | -| subAction | The sub action to perform. It can be `commonFields`, `pushToService`, `handshake`, and `getIncident` | string | +| subAction | The sub action to perform. It can be `getFields`, `pushToService`, `handshake`, and `getIncident` | string | | subActionParams | The parameters of the sub action | object | #### `subActionParams (pushToService)` @@ -681,9 +681,9 @@ ID: `.resilient` | incidentTypes | An array with the ids of IBM Resilient incident types. | number[] _(optional)_ | | severityCode | IBM Resilient id of the severity code. | number _(optional)_ | -#### `subActionParams (commonFields)` +#### `subActionParams (getFields)` -No parameters for `commonFields` sub-action. Provide an empty object `{}`. +No parameters for `getFields` sub-action. Provide an empty object `{}`. # Command Line Utility diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts index aff071eb88f26..5a7617ada1bf0 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts @@ -5,7 +5,7 @@ */ import { Logger } from '../../../../../../src/core/server'; -import { externalServiceMock, mapping, apiParams, jiraCommonFields } from './mocks'; +import { externalServiceMock, mapping, apiParams } from './mocks'; import { ExternalService } from './types'; import { api } from './api'; let mockedLogger: jest.Mocked; @@ -382,16 +382,6 @@ describe('api', () => { }); }); - describe('commonFields', () => { - test('it returns the fields correctly', async () => { - const res = await api.commonFields({ - externalService, - params: {}, - }); - expect(res).toEqual(jiraCommonFields); - }); - }); - describe('getIssues', () => { test('it returns the issues correctly', async () => { const res = await api.issues({ diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts index b194dce7cd466..feeb69b1d1a0e 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts @@ -40,8 +40,8 @@ const getIssueTypesHandler = async ({ externalService }: GetIssueTypesHandlerArg return res; }; -const getCommonFieldsHandler = async ({ externalService }: GetCommonFieldsHandlerArgs) => { - const res = await externalService.getCommonFields(); +const getFieldsHandler = async ({ externalService }: GetCommonFieldsHandlerArgs) => { + const res = await externalService.getFields(); return res; }; @@ -163,7 +163,7 @@ const pushToServiceHandler = async ({ }; export const api: ExternalServiceApi = { - commonFields: getCommonFieldsHandler, + getFields: getFieldsHandler, handshake: handshakeHandler, pushToService: pushToServiceHandler, getIncident: getIncidentHandler, diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts index 6ea8028f1b08f..c70c0810926f4 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts @@ -40,7 +40,7 @@ interface GetActionTypeParams { } const supportedSubActions: string[] = [ - 'commonFields', + 'getFields', 'pushToService', 'issueTypes', 'fieldsByIssueType', @@ -146,8 +146,8 @@ async function executor( }); } - if (subAction === 'commonFields') { - data = await api.commonFields({ + if (subAction === 'getFields') { + data = await api.getFields({ externalService, params: subActionParams, }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts index 9ab89d9ad243c..660c82dc38b84 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts @@ -73,7 +73,7 @@ const createMock = (): jest.Mocked => { key: 'RJ-107', title: 'Test title', })), - getCommonFields: jest.fn().mockImplementation(() => jiraCommonFields), + getFields: jest.fn().mockImplementation(() => jiraCommonFields), }; service.createComment.mockImplementationOnce(() => @@ -98,74 +98,6 @@ const createMock = (): jest.Mocked => { const externalServiceMock = { create: createMock, }; -const jiraFields = [ - { - id: 'issuetype', - key: 'issuetype', - name: 'Issue Type', - custom: false, - orderable: true, - navigable: true, - searchable: true, - clauseNames: ['issuetype', 'type'], - schema: { type: 'issuetype', system: 'issuetype' }, - }, - { - id: 'parent', - key: 'parent', - name: 'Parent', - custom: false, - orderable: false, - navigable: true, - searchable: false, - clauseNames: ['parent'], - }, - { - id: 'summary', - key: 'summary', - name: 'Summary', - custom: false, - orderable: true, - navigable: true, - searchable: true, - clauseNames: ['summary'], - schema: { type: 'string', system: 'summary' }, - }, - { - id: 'reporter', - key: 'reporter', - name: 'Reporter', - custom: false, - orderable: true, - navigable: true, - searchable: true, - clauseNames: ['reporter'], - schema: { type: 'user', system: 'reporter' }, - }, - { - id: 'priority', - key: 'priority', - name: 'Priority', - custom: false, - orderable: true, - navigable: true, - searchable: true, - clauseNames: ['priority'], - schema: { type: 'priority', system: 'priority' }, - }, - { - id: 'description', - key: 'description', - name: 'Description', - custom: false, - orderable: true, - navigable: true, - searchable: true, - clauseNames: ['description'], - schema: { type: 'string', system: 'description' }, - }, -]; -const jiraCommonFields = jiraFields.filter(({ id }) => id === 'summary' || id === 'description'); const mapping: Map> = new Map(); mapping.set('title', { @@ -226,4 +158,4 @@ const apiParams: PushToServiceApiParams = { externalObject: { summary: 'Incident title', description: 'Incident description' }, }; -export { jiraCommonFields, jiraFields, externalServiceMock, mapping, executorParams, apiParams }; +export { externalServiceMock, mapping, executorParams, apiParams }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts index a95387f390d08..70b60ada9c386 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts @@ -67,7 +67,7 @@ export const ExecutorSubActionGetIssueParamsSchema = schema.object({ id: schema. export const ExecutorParamsSchema = schema.oneOf([ schema.object({ - subAction: schema.literal('commonFields'), + subAction: schema.literal('getFields'), subActionParams: ExecutorSubActionCommonFieldsParamsSchema, }), schema.object({ diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts index 4035bf1df30c5..2165ba56428c9 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts @@ -11,7 +11,6 @@ import * as utils from '../lib/axios_utils'; import { ExternalService } from './types'; import { Logger } from '../../../../../../src/core/server'; import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; -import { jiraCommonFields, jiraFields } from './mocks'; const logger = loggingSystemMock.create().get() as jest.Mocked; interface ResponseError extends Error { @@ -58,8 +57,10 @@ const fieldsResponse = { id: '10006', name: 'Task', fields: { - summary: { fieldId: 'summary' }, + summary: { required: true, schema: { type: 'string' }, fieldId: 'summary' }, priority: { + required: false, + schema: { type: 'string' }, fieldId: 'priority', allowedValues: [ { @@ -766,6 +767,8 @@ describe('Jira service', () => { expect(res).toEqual({ priority: { + required: false, + schema: { type: 'string' }, allowedValues: [ { id: '1', name: 'Highest' }, { id: '2', name: 'High' }, @@ -775,7 +778,12 @@ describe('Jira service', () => { ], defaultValue: { id: '3', name: 'Medium' }, }, - summary: { allowedValues: [], defaultValue: {} }, + summary: { + required: true, + schema: { type: 'string' }, + allowedValues: [], + defaultValue: {}, + }, }); }); @@ -838,8 +846,10 @@ describe('Jira service', () => { requestMock.mockImplementationOnce(() => ({ data: { values: [ - { fieldId: 'summary' }, + { required: true, schema: { type: 'string' }, fieldId: 'summary' }, { + required: false, + schema: { type: 'string' }, fieldId: 'priority', allowedValues: [ { @@ -860,10 +870,17 @@ describe('Jira service', () => { expect(res).toEqual({ priority: { + required: false, + schema: { type: 'string' }, allowedValues: [{ id: '3', name: 'Medium' }], defaultValue: { id: '3', name: 'Medium' }, }, - summary: { allowedValues: [], defaultValue: {} }, + summary: { + required: true, + schema: { type: 'string' }, + allowedValues: [], + defaultValue: {}, + }, }); }); @@ -882,8 +899,10 @@ describe('Jira service', () => { requestMock.mockImplementationOnce(() => ({ data: { values: [ - { fieldId: 'summary' }, + { required: true, schema: { type: 'string' }, fieldId: 'summary' }, { + required: true, + schema: { type: 'string' }, fieldId: 'priority', allowedValues: [ { @@ -1027,10 +1046,9 @@ describe('Jira service', () => { }); }); - describe('getCommonFields', () => { + describe('getFields', () => { const callMocks = () => { requestMock - .mockImplementationOnce(() => ({ data: jiraFields })) .mockImplementationOnce(() => ({ data: { capabilities: { @@ -1069,9 +1087,11 @@ describe('Jira service', () => { .mockImplementationOnce(() => ({ data: { values: [ - { fieldId: 'summary' }, - { fieldId: 'description' }, + { required: true, schema: { type: 'string' }, fieldId: 'summary' }, + { required: true, schema: { type: 'string' }, fieldId: 'description' }, { + required: false, + schema: { type: 'string' }, fieldId: 'priority', allowedValues: [ { @@ -1089,7 +1109,10 @@ describe('Jira service', () => { })) .mockImplementationOnce(() => ({ data: { - values: [{ fieldId: 'summary' }, { fieldId: 'description' }], + values: [ + { required: true, schema: { type: 'string' }, fieldId: 'summary' }, + { required: true, schema: { type: 'string' }, fieldId: 'description' }, + ], }, })); }; @@ -1098,9 +1121,8 @@ describe('Jira service', () => { }); test('it should call request with correct arguments', async () => { callMocks(); - await service.getCommonFields(); + await service.getFields(); const callUrls = [ - 'https://siem-kibana.atlassian.net/rest/api/2/field', 'https://siem-kibana.atlassian.net/rest/capabilities', 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes', 'https://siem-kibana.atlassian.net/rest/capabilities', @@ -1114,8 +1136,21 @@ describe('Jira service', () => { }); test('it returns common fields correctly', async () => { callMocks(); - const res = await service.getCommonFields(); - expect(res).toEqual(jiraCommonFields); + const res = await service.getFields(); + expect(res).toEqual({ + description: { + allowedValues: [], + defaultValue: {}, + required: true, + schema: { type: 'string' }, + }, + summary: { + allowedValues: [], + defaultValue: {}, + required: true, + schema: { type: 'string' }, + }, + }); }); test('it should throw an error', async () => { @@ -1124,8 +1159,8 @@ describe('Jira service', () => { error.response = { data: { errors: { summary: 'Required field' } } }; throw error; }); - await expect(service.getCommonFields()).rejects.toThrow( - '[Action][Jira]: Unable to get fields. Error: An error has occurred Reason: Required field' + await expect(service.getFields()).rejects.toThrow( + '[Action][Jira]: Unable to get capabilities. Error: An error has occurred. Reason: Required field' ); }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts index 08b0b356b5976..5f583d31a70e7 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts @@ -21,6 +21,9 @@ import { ExternalServiceCommentResponse, ExternalServiceIncidentResponse, ExternalServiceFields, + FieldSchema, + GetFieldsByIssueTypeResponse, + GetCommonFieldsResponse, } from './types'; import * as i18n from './translations'; @@ -47,7 +50,6 @@ export const createExternalService = ( throw Error(`[Action]${i18n.NAME}: Wrong configuration.`); } - const fieldsUrl = `${url}/${BASE_URL}/field`; const incidentUrl = `${url}/${BASE_URL}/issue`; const capabilitiesUrl = `${url}/${CAPABILITIES_URL}`; const commentUrl = `${incidentUrl}/{issueId}/comment`; @@ -129,14 +131,21 @@ export const createExternalService = ( issueTypes.map((type) => ({ id: type.id, name: type.name })); const normalizeFields = (fields: { - [key: string]: { allowedValues?: Array<{}>; defaultValue?: {} }; + [key: string]: { + allowedValues?: Array<{}>; + defaultValue?: {}; + required: boolean; + schema: FieldSchema; + }; }) => Object.keys(fields ?? {}).reduce((fieldsAcc, fieldKey) => { return { ...fieldsAcc, [fieldKey]: { + required: fields[fieldKey]?.required, allowedValues: fields[fieldKey]?.allowedValues ?? [], defaultValue: fields[fieldKey]?.defaultValue ?? {}, + schema: fields[fieldKey]?.schema, }, }; }, {}); @@ -152,28 +161,6 @@ export const createExternalService = ( title: issue.fields?.summary ?? null, }); - const getFields = async (): Promise => { - try { - const res = await request({ - axios: axiosInstance, - url: fieldsUrl, - logger, - proxySettings, - }); - - return res.data; - } catch (error) { - throw new Error( - getErrorMessage( - i18n.NAME, - `Unable to get fields. Error: ${error.message} Reason: ${createErrorMessage( - error.response?.data - )}` - ) - ); - } - }; - const getIncident = async (id: string) => { try { const res = await request({ @@ -400,6 +387,7 @@ export const createExternalService = ( }); const fields = res.data.projects[0]?.issuetypes[0]?.fields || {}; + return normalizeFields(fields); } else { const res = await request({ @@ -431,19 +419,24 @@ export const createExternalService = ( } }; - const getCommonFields = async () => { + const getFields = async () => { try { - const [fields, issueTypes] = await Promise.all([getFields(), getIssueTypes()]); - const fieldTypes = await Promise.all( + const issueTypes = await getIssueTypes(); + const fieldsPerIssueType = await Promise.all( issueTypes.map((issueType) => getFieldsByIssueType(issueType.id)) ); - const commonFields = fieldTypes.reduce((acc: string[], fieldTypesByIssue) => { - const newKeys = Object.keys(fieldTypesByIssue); - return acc.length === 0 - ? [...newKeys] - : acc.reduce((add: string[], key) => (newKeys.includes(key) ? [...add, key] : add), []); - }, []); - return fields.filter((f) => commonFields.includes(f.id)); + return fieldsPerIssueType.reduce((acc: GetCommonFieldsResponse, fieldTypesByIssue) => { + const currentListOfFields = Object.keys(acc); + return currentListOfFields.length === 0 + ? fieldTypesByIssue + : currentListOfFields.reduce( + (add: GetCommonFieldsResponse, field) => + Object.keys(fieldTypesByIssue).includes(field) + ? { ...add, [field]: acc[field] } + : add, + {} + ); + }, {}); } catch (error) { // errors that happen here would be thrown in the contained async calls throw error; @@ -502,7 +495,7 @@ export const createExternalService = ( }; return { - getCommonFields, + getFields, getIncident, createIncident, updateIncident, diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts index 685f1f5352049..e142637010a98 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts @@ -95,13 +95,18 @@ export interface ExternalServiceFields { schema: FieldsSchema; searchable: boolean; } -export type GetCommonFieldsResponse = ExternalServiceFields[]; export type GetIssueTypesResponse = Array<{ id: string; name: string }>; + +export interface FieldSchema { + type: string; + items?: string; +} export type GetFieldsByIssueTypeResponse = Record< string, - { allowedValues: Array<{}>; defaultValue: {} } + { allowedValues: Array<{}>; defaultValue: {}; required: boolean; schema: FieldSchema } >; +export type GetCommonFieldsResponse = GetFieldsByIssueTypeResponse; export type GetIssuesResponse = Array<{ id: string; key: string; title: string }>; export interface GetIssueResponse { @@ -113,7 +118,7 @@ export interface GetIssueResponse { export interface ExternalService { createComment: (params: CreateCommentParams) => Promise; createIncident: (params: CreateIncidentParams) => Promise; - getCommonFields: () => Promise; + getFields: () => Promise; getCapabilities: () => Promise; getFieldsByIssueType: (issueTypeId: string) => Promise; getIncident: (id: string) => Promise; @@ -201,7 +206,7 @@ export interface GetIssueHandlerArgs { } export interface ExternalServiceApi { - commonFields: (args: GetCommonFieldsHandlerArgs) => Promise; + getFields: (args: GetCommonFieldsHandlerArgs) => Promise; getIncident: (args: GetIncidentApiHandlerArgs) => Promise; handshake: (args: HandshakeApiHandlerArgs) => Promise; issueTypes: (args: GetIssueTypesHandlerArgs) => Promise; diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/api.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/api.ts index 1dd936962d1f5..29f2594d2b6f8 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/api.ts @@ -33,8 +33,8 @@ const getIncidentHandler = async ({ params, }: GetIncidentApiHandlerArgs) => {}; -const getCommonFieldsHandler = async ({ externalService }: GetCommonFieldsHandlerArgs) => { - const res = await externalService.getCommonFields(); +const getFieldsHandler = async ({ externalService }: GetCommonFieldsHandlerArgs) => { + const res = await externalService.getFields(); return res; }; const getIncidentTypesHandler = async ({ externalService }: GetIncidentTypesHandlerArgs) => { @@ -141,7 +141,7 @@ const pushToServiceHandler = async ({ }; export const api: ExternalServiceApi = { - commonFields: getCommonFieldsHandler, + getFields: getFieldsHandler, getIncident: getIncidentHandler, handshake: handshakeHandler, incidentTypes: getIncidentTypesHandler, diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/index.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/index.ts index 13e0cf4fe2205..6203dda4120f5 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/index.ts @@ -38,12 +38,7 @@ interface GetActionTypeParams { configurationUtilities: ActionsConfigurationUtilities; } -const supportedSubActions: string[] = [ - 'commonFields', - 'pushToService', - 'incidentTypes', - 'severity', -]; +const supportedSubActions: string[] = ['getFields', 'pushToService', 'incidentTypes', 'severity']; // action type definition export function getActionType( @@ -128,11 +123,11 @@ async function executor( logger.debug(`response push to service for incident id: ${data.id}`); } - if (subAction === 'commonFields') { - const commonFieldsParams = subActionParams as ExecutorSubActionCommonFieldsParams; - data = await api.commonFields({ + if (subAction === 'getFields') { + const getFieldsParams = subActionParams as ExecutorSubActionCommonFieldsParams; + data = await api.getFields({ externalService, - params: commonFieldsParams, + params: getFieldsParams, }); } diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/mocks.ts index 51f58077044c8..2b2a22a66b709 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/mocks.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/mocks.ts @@ -276,7 +276,7 @@ export const resilientFields = [ const createMock = (): jest.Mocked => { const service = { - getCommonFields: jest.fn().mockImplementation(() => Promise.resolve(resilientFields)), + getFields: jest.fn().mockImplementation(() => Promise.resolve(resilientFields)), getIncident: jest.fn().mockImplementation(() => Promise.resolve({ id: '1', diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/schema.ts index aadd59e60e471..c7ceba94140fb 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/schema.ts @@ -60,7 +60,7 @@ export const ExecutorSubActionGetSeverityParamsSchema = schema.object({}); export const ExecutorParamsSchema = schema.oneOf([ schema.object({ - subAction: schema.literal('commonFields'), + subAction: schema.literal('getFields'), subActionParams: ExecutorSubActionCommonFieldsParamsSchema, }), schema.object({ diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.test.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.test.ts index 19c67e4695b5a..ecf246cb8fe3c 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.test.ts @@ -584,12 +584,12 @@ describe('IBM Resilient service', () => { }); }); - describe('getCommonFields', () => { + describe('getFields', () => { test('it should call request with correct arguments', async () => { requestMock.mockImplementation(() => ({ data: resilientFields, })); - await service.getCommonFields(); + await service.getFields(); expect(requestMock).toHaveBeenCalledWith({ axios, @@ -601,7 +601,7 @@ describe('IBM Resilient service', () => { requestMock.mockImplementation(() => ({ data: resilientFields, })); - const res = await service.getCommonFields(); + const res = await service.getFields(); expect(res).toEqual(resilientFields); }); @@ -609,7 +609,7 @@ describe('IBM Resilient service', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - await expect(service.getCommonFields()).rejects.toThrow( + await expect(service.getFields()).rejects.toThrow( 'Unable to get fields. Error: An error has occurred' ); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts index be4ebf9cb662e..a13204f8bb1d8 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts @@ -303,7 +303,7 @@ export const createExternalService = ( } }; - const getCommonFields = async () => { + const getFields = async () => { try { const res = await request({ axios: axiosInstance, @@ -320,7 +320,7 @@ export const createExternalService = ( return { createComment, createIncident, - getCommonFields, + getFields, getIncident, getIncidentTypes, getSeverity, diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/types.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/types.ts index 28269828fbae4..a70420b30a092 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/types.ts @@ -101,7 +101,7 @@ export type GetSeverityResponse = Array<{ id: string; name: string }>; export interface ExternalService { createComment: (params: CreateCommentParams) => Promise; createIncident: (params: CreateIncidentParams) => Promise; - getCommonFields: () => Promise; + getFields: () => Promise; getIncident: (id: string) => Promise; getIncidentTypes: () => Promise; getSeverity: () => Promise; @@ -166,7 +166,7 @@ export interface PushToServiceResponse extends ExternalServiceIncidentResponse { } export interface ExternalServiceApi { - commonFields: (args: GetCommonFieldsHandlerArgs) => Promise; + getFields: (args: GetCommonFieldsHandlerArgs) => Promise; handshake: (args: HandshakeApiHandlerArgs) => Promise; pushToService: (args: PushToServiceApiHandlerArgs) => Promise; getIncident: (args: GetIncidentApiHandlerArgs) => Promise; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts index cef837de74229..4683b661e21da 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts @@ -621,9 +621,9 @@ describe('api', () => { }); }); - describe('commonFields', () => { + describe('getFields', () => { test('it returns the fields correctly', async () => { - const res = await api.commonFields({ + const res = await api.getFields({ externalService, params: {}, }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts index 3b58546668284..fbd8fdd635d70 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts @@ -129,15 +129,15 @@ const pushToServiceHandler = async ({ return res; }; -const getCommonFieldsHandler = async ({ +const getFieldsHandler = async ({ externalService, }: GetCommonFieldsHandlerArgs): Promise => { - const res = await externalService.getCommonFields(); + const res = await externalService.getFields(); return res; }; export const api: ExternalServiceApi = { - commonFields: getCommonFieldsHandler, + getFields: getFieldsHandler, getIncident: getIncidentHandler, handshake: handshakeHandler, pushToService: pushToServiceHandler, diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts index f0b34821ad720..d1182b0d3b2fa 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts @@ -65,7 +65,7 @@ export function getActionType( } // action executor -const supportedSubActions: string[] = ['commonFields', 'pushToService']; +const supportedSubActions: string[] = ['getFields', 'pushToService']; async function executor( { logger }: { logger: Logger }, execOptions: ActionTypeExecutorOptions< @@ -119,11 +119,11 @@ async function executor( logger.debug(`response push to service for incident id: ${data.id}`); } - if (subAction === 'commonFields') { - const commonFieldsParams = subActionParams as ExecutorSubActionCommonFieldsParams; - data = await api.commonFields({ + if (subAction === 'getFields') { + const getFieldsParams = subActionParams as ExecutorSubActionCommonFieldsParams; + data = await api.getFields({ externalService, - params: commonFieldsParams, + params: getFieldsParams, }); } diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts index f82028fa47e98..2351be36a50c4 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts @@ -36,7 +36,7 @@ export const serviceNowCommonFields = [ ]; const createMock = (): jest.Mocked => { const service = { - getCommonFields: jest.fn().mockImplementation(() => Promise.resolve(serviceNowCommonFields)), + getFields: jest.fn().mockImplementation(() => Promise.resolve(serviceNowCommonFields)), getIncident: jest.fn().mockImplementation(() => Promise.resolve({ short_description: 'title from servicenow', diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts index f6b89b793b990..77c48aab1f309 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts @@ -28,7 +28,7 @@ export const ExternalIncidentServiceSecretConfigurationSchema = schema.object( ); export const ExecutorSubActionSchema = schema.oneOf([ - schema.literal('commonFields'), + schema.literal('getFields'), schema.literal('getIncident'), schema.literal('pushToService'), schema.literal('handshake'), @@ -58,7 +58,7 @@ export const ExecutorSubActionCommonFieldsParamsSchema = schema.object({}); export const ExecutorParamsSchema = schema.oneOf([ schema.object({ - subAction: schema.literal('commonFields'), + subAction: schema.literal('getFields'), subActionParams: ExecutorSubActionCommonFieldsParamsSchema, }), schema.object({ diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts index d21c51246fe8c..8ec80be1e2b09 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts @@ -236,12 +236,12 @@ describe('ServiceNow service', () => { }); }); - describe('getCommonFields', () => { + describe('getFields', () => { test('it should call request with correct arguments', async () => { requestMock.mockImplementation(() => ({ data: { result: serviceNowCommonFields }, })); - await service.getCommonFields(); + await service.getFields(); expect(requestMock).toHaveBeenCalledWith({ axios, @@ -254,7 +254,7 @@ describe('ServiceNow service', () => { requestMock.mockImplementation(() => ({ data: { result: serviceNowCommonFields }, })); - const res = await service.getCommonFields(); + const res = await service.getFields(); expect(res).toEqual(serviceNowCommonFields); }); @@ -262,7 +262,7 @@ describe('ServiceNow service', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - await expect(service.getCommonFields()).rejects.toThrow( + await expect(service.getFields()).rejects.toThrow( 'Unable to get common fields. Error: An error has occurred' ); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts index 5855f906c839e..57f7176e2353c 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts @@ -128,7 +128,7 @@ export const createExternalService = ( } }; - const getCommonFields = async () => { + const getFields = async () => { try { const res = await request({ axios: axiosInstance, @@ -148,7 +148,7 @@ export const createExternalService = ( return { createIncident, findIncidents, - getCommonFields, + getFields, getIncident, updateIncident, }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts index 76026358d530b..0ee03f883ec05 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts @@ -66,7 +66,7 @@ export interface PushToServiceResponse extends ExternalServiceIncidentResponse { export type ExternalServiceParams = Record; export interface ExternalService { - getCommonFields: () => Promise; + getFields: () => Promise; getIncident: (id: string) => Promise; createIncident: (params: ExternalServiceParams) => Promise; updateIncident: (params: ExternalServiceParams) => Promise; @@ -127,7 +127,7 @@ export interface GetCommonFieldsHandlerArgs { } export interface ExternalServiceApi { - commonFields: (args: GetCommonFieldsHandlerArgs) => Promise; + getFields: (args: GetCommonFieldsHandlerArgs) => Promise; handshake: (args: HandshakeApiHandlerArgs) => Promise; pushToService: (args: PushToServiceApiHandlerArgs) => Promise; getIncident: (args: GetIncidentApiHandlerArgs) => Promise; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts index 9de0f53bd7265..4e9293b74c99e 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts @@ -333,7 +333,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', }); }); }); @@ -351,7 +351,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', }); }); }); @@ -374,7 +374,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', }); }); }); @@ -402,7 +402,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', }); }); }); @@ -430,7 +430,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]', }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/resilient.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/resilient.ts index 7e862c2499173..34c1c757ab119 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/resilient.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/resilient.ts @@ -334,7 +334,7 @@ export default function resilientTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', }); }); }); @@ -352,7 +352,7 @@ export default function resilientTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', }); }); }); @@ -375,7 +375,7 @@ export default function resilientTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', }); }); }); @@ -403,7 +403,7 @@ export default function resilientTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', }); }); }); @@ -431,7 +431,7 @@ export default function resilientTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]', }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts index 1347b4d078b0a..5b4db53a59a41 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts @@ -328,7 +328,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]', }); }); }); @@ -346,7 +346,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]', }); }); }); @@ -369,7 +369,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]', }); }); }); @@ -397,7 +397,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments.0.commentId]: expected value of type [string] but got [undefined]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments.0.commentId]: expected value of type [string] but got [undefined]', }); }); }); @@ -425,7 +425,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [commonFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments.0.comment]: expected value of type [string] but got [undefined]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments.0.comment]: expected value of type [string] but got [undefined]', }); }); }); From 4fe928224d07a8bd5ffb929d3c5c0285a5382ba7 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Thu, 5 Nov 2020 13:03:29 -0700 Subject: [PATCH 13/13] fix types --- .../server/builtin_action_types/jira/mocks.ts | 15 +++++++++++++- .../builtin_action_types/jira/service.ts | 20 +++++++++---------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts index 660c82dc38b84..87a0f156a0c2a 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts @@ -73,7 +73,20 @@ const createMock = (): jest.Mocked => { key: 'RJ-107', title: 'Test title', })), - getFields: jest.fn().mockImplementation(() => jiraCommonFields), + getFields: jest.fn().mockImplementation(() => ({ + description: { + allowedValues: [], + defaultValue: {}, + required: true, + schema: { type: 'string' }, + }, + summary: { + allowedValues: [], + defaultValue: {}, + required: true, + schema: { type: 'string' }, + }, + })), }; service.createComment.mockImplementationOnce(() => diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts index 5f583d31a70e7..b3c5bb4a84de5 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts @@ -8,22 +8,20 @@ import axios from 'axios'; import { Logger } from '../../../../../../src/core/server'; import { - ExternalServiceCredentials, - ExternalService, - CreateIncidentParams, - UpdateIncidentParams, - JiraPublicConfigurationType, - JiraSecretConfigurationType, - Fields, CreateCommentParams, - Incident, - ResponseError, + CreateIncidentParams, + ExternalService, ExternalServiceCommentResponse, + ExternalServiceCredentials, ExternalServiceIncidentResponse, - ExternalServiceFields, + Fields, FieldSchema, - GetFieldsByIssueTypeResponse, GetCommonFieldsResponse, + Incident, + JiraPublicConfigurationType, + JiraSecretConfigurationType, + ResponseError, + UpdateIncidentParams, } from './types'; import * as i18n from './translations';