-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SIEM][CASE] Refactor Connectors - Jira Connector #63450
Changes from 34 commits
e42a338
812b4b2
f6708ac
04cc044
71324a7
f4ab071
1273434
c629c13
cb21062
4e256ff
aadf8bf
3352ca8
4beadfe
e1484c8
c9b1267
6b481c9
84b4d13
4af3820
eb166e2
0ed84b1
af483b9
57d6107
aa6fa7c
aee3e47
329d083
ce9db2a
ed41eb6
66b09b7
9245748
9c54ea4
1a64bf6
3603141
269d164
42fbd47
102826e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { | ||
ExternalServiceApi, | ||
ExternalServiceParams, | ||
PushToServiceResponse, | ||
GetIncidentApiHandlerArgs, | ||
HandshakeApiHandlerArgs, | ||
PushToServiceApiHandlerArgs, | ||
} from './types'; | ||
import { prepareFieldsForTransformation, transformFields, transformComments } from './utils'; | ||
|
||
const handshakeHandler = async ({ | ||
externalService, | ||
mapping, | ||
params, | ||
}: HandshakeApiHandlerArgs) => {}; | ||
const getIncidentHandler = async ({ | ||
externalService, | ||
mapping, | ||
params, | ||
}: GetIncidentApiHandlerArgs) => {}; | ||
|
||
const pushToServiceHandler = async ({ | ||
externalService, | ||
mapping, | ||
params, | ||
}: PushToServiceApiHandlerArgs): Promise<PushToServiceResponse> => { | ||
const { externalId, comments } = params; | ||
const updateIncident = externalId ? true : false; | ||
const defaultPipes = updateIncident ? ['informationUpdated'] : ['informationCreated']; | ||
let currentIncident: ExternalServiceParams | undefined; | ||
let res: PushToServiceResponse; | ||
|
||
if (externalId) { | ||
currentIncident = await externalService.getIncident(externalId); | ||
} | ||
|
||
const fields = prepareFieldsForTransformation({ | ||
params, | ||
mapping, | ||
defaultPipes, | ||
}); | ||
|
||
const incident = transformFields({ | ||
params, | ||
fields, | ||
currentIncident, | ||
}); | ||
|
||
if (updateIncident) { | ||
res = await externalService.updateIncident({ incidentId: externalId, incident }); | ||
} else { | ||
res = await externalService.createIncident({ incident }); | ||
} | ||
|
||
if ( | ||
comments && | ||
Array.isArray(comments) && | ||
comments.length > 0 && | ||
mapping.get('comments')?.actionType !== 'nothing' | ||
) { | ||
const commentsTransformed = transformComments(comments, ['informationAdded']); | ||
|
||
res.comments = []; | ||
for (const currentComment of commentsTransformed) { | ||
const comment = await externalService.createComment({ | ||
incidentId: res.id, | ||
comment: currentComment, | ||
field: mapping.get('comments')?.target ?? 'comments', | ||
}); | ||
res.comments = [ | ||
...(res.comments ?? []), | ||
{ | ||
commentId: comment.commentId, | ||
pushedDate: comment.pushedDate, | ||
}, | ||
]; | ||
} | ||
} | ||
|
||
return res; | ||
}; | ||
|
||
export const api: ExternalServiceApi = { | ||
handshake: handshakeHandler, | ||
pushToService: pushToServiceHandler, | ||
getIncident: getIncidentHandler, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { schema } from '@kbn/config-schema'; | ||
|
||
export const MappingActionType = schema.oneOf([ | ||
schema.literal('nothing'), | ||
schema.literal('overwrite'), | ||
schema.literal('append'), | ||
]); | ||
|
||
export const MapRecordSchema = schema.object({ | ||
source: schema.string(), | ||
target: schema.string(), | ||
actionType: MappingActionType, | ||
}); | ||
|
||
export const CaseConfigurationSchema = schema.object({ | ||
mapping: schema.arrayOf(MapRecordSchema), | ||
}); | ||
|
||
export const ExternalIncidentServiceConfiguration = { | ||
apiUrl: schema.string(), | ||
casesConfiguration: CaseConfigurationSchema, | ||
}; | ||
|
||
export const ExternalIncidentServiceConfigurationSchema = schema.object( | ||
ExternalIncidentServiceConfiguration | ||
); | ||
|
||
export const ExternalIncidentServiceSecretConfiguration = { | ||
password: schema.string(), | ||
username: schema.string(), | ||
}; | ||
|
||
export const ExternalIncidentServiceSecretConfigurationSchema = schema.object( | ||
ExternalIncidentServiceSecretConfiguration | ||
); | ||
|
||
export const UserSchema = schema.object({ | ||
fullName: schema.oneOf([schema.nullable(schema.string()), schema.maybe(schema.string())]), | ||
username: schema.oneOf([schema.nullable(schema.string()), schema.maybe(schema.string())]), | ||
}); | ||
|
||
const EntityInformation = { | ||
createdAt: schema.string(), | ||
createdBy: UserSchema, | ||
updatedAt: schema.nullable(schema.string()), | ||
updatedBy: schema.nullable(UserSchema), | ||
}; | ||
|
||
export const EntityInformationSchema = schema.object(EntityInformation); | ||
|
||
export const CommentSchema = schema.object({ | ||
commentId: schema.string(), | ||
comment: schema.string(), | ||
version: schema.maybe(schema.string()), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should be using There are a couple of other references to I'll note that it's unwieldy to use the TS types generated from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right about |
||
...EntityInformation, | ||
}); | ||
|
||
export const ExecutorSubActionSchema = schema.oneOf([ | ||
schema.literal('getIncident'), | ||
schema.literal('pushToService'), | ||
schema.literal('handshake'), | ||
]); | ||
|
||
export const ExecutorSubActionPushParamsSchema = schema.object({ | ||
caseId: schema.string(), | ||
title: schema.string(), | ||
description: schema.maybe(schema.string()), | ||
comments: schema.maybe(schema.arrayOf(CommentSchema)), | ||
externalId: schema.nullable(schema.string()), | ||
...EntityInformation, | ||
}); | ||
|
||
export const ExecutorSubActionGetIncidentParamsSchema = schema.object({ | ||
externalId: schema.string(), | ||
}); | ||
|
||
// Reserved for future implementation | ||
export const ExecutorSubActionHandshakeParamsSchema = schema.object({}); | ||
|
||
export const ExecutorParamsSchema = schema.oneOf([ | ||
cnasikas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
schema.object({ | ||
subAction: schema.literal('getIncident'), | ||
subActionParams: ExecutorSubActionGetIncidentParamsSchema, | ||
}), | ||
schema.object({ | ||
subAction: schema.literal('handshake'), | ||
subActionParams: ExecutorSubActionHandshakeParamsSchema, | ||
}), | ||
schema.object({ | ||
subAction: schema.literal('pushToService'), | ||
subActionParams: ExecutorSubActionPushParamsSchema, | ||
}), | ||
]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a note about the use of
schema.maybe()
in another comment, but this one seems ... more interesting. I think technically you can just usefullName: schema.nullable(schema.string())
, but am curious if you had to do it this way for some other reason. Even for cases likeMappingActionType
above, I've instead sometimes just set the schema to a string, and validated the fixed set of literals in a custom validator, to produce a better error message for validation.Probably worthwhile noting that the validation error messages produced from
schema.oneOf()
are quite verbose, and can be a little confusing.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a good reason for that either. Probably I did it to match
fullname: string | undefined | null
. You are right, no need for that.About
schema.oneOf
you are right. It's quite verbose and difficult to catch. I tried to use the validate function but there was a bug (#64906). I would follow your advice and create a custom validator to produce better error messages for our schema in another PR.