Skip to content

Commit

Permalink
ITSM: Add category & subcategory fields
Browse files Browse the repository at this point in the history
  • Loading branch information
cnasikas committed Feb 6, 2021
1 parent 0f42ae2 commit d6bfcef
Show file tree
Hide file tree
Showing 16 changed files with 364 additions and 108 deletions.
2 changes: 2 additions & 0 deletions x-pack/plugins/actions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,8 @@ The following table describes the properties of the `incident` object.
| severity | The name of the severity in ServiceNow. | string _(optional)_ |
| urgency | The name of the urgency in ServiceNow. | string _(optional)_ |
| impact | The name of the impact in ServiceNow. | string _(optional)_ |
| category | The name of the category in ServiceNow. | string _(optional)_ |
| subcategory | The name of the subcategory in ServiceNow. | string _(optional)_ |

#### `subActionParams (getFields)`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ const CommonAttributes = {
short_description: schema.string(),
description: schema.nullable(schema.string()),
externalId: schema.nullable(schema.string()),
category: schema.nullable(schema.string()),
subcategory: schema.nullable(schema.string()),
};

// Schema for ServiceNow Incident Management (ITSM)
Expand All @@ -62,13 +64,11 @@ export const ExecutorSubActionPushParamsSchemaITSM = schema.object({
export const ExecutorSubActionPushParamsSchemaSIR = schema.object({
incident: schema.object({
...CommonAttributes,
category: schema.nullable(schema.string()),
dest_ip: schema.nullable(schema.string()),
malware_hash: schema.nullable(schema.string()),
malware_url: schema.nullable(schema.string()),
priority: schema.nullable(schema.string()),
source_ip: schema.nullable(schema.string()),
subcategory: schema.nullable(schema.string()),
priority: schema.nullable(schema.string()),
}),
comments: CommentsSchema,
});
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/case/common/api/connectors/servicenow_itsm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export const ServiceNowITSMFieldsRT = rt.type({
impact: rt.union([rt.string, rt.null]),
severity: rt.union([rt.string, rt.null]),
urgency: rt.union([rt.string, rt.null]),
category: rt.union([rt.string, rt.null]),
subcategory: rt.union([rt.string, rt.null]),
});

export type ServiceNowITSMFieldsType = rt.TypeOf<typeof ServiceNowITSMFieldsRT>;
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { ServiceNowITSMFieldsType, ConnectorServiceNowITSMTypeFields } from '../
import { ExternalServiceFormatter } from '../types';

const format: ExternalServiceFormatter<ServiceNowITSMFieldsType>['format'] = async (theCase) => {
const { severity = null, urgency = null, impact = null } =
const { severity = null, urgency = null, impact = null, category = null, subcategory = null } =
(theCase.connector.fields as ConnectorServiceNowITSMTypeFields['fields']) ?? {};
return { severity, urgency, impact };
return { severity, urgency, impact, category, subcategory };
};

export const serviceNowITSMExternalServiceFormatter: ExternalServiceFormatter<ServiceNowITSMFieldsType> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import { serviceNowITSMExternalServiceFormatter } from './itsm_formatter';

describe('ITSM formatter', () => {
const theCase = {
connector: { fields: { severity: '2', urgency: '2', impact: '2' } },
connector: {
fields: { severity: '2', urgency: '2', impact: '2', category: 'software', subcategory: 'os' },
},
} as CaseResponse;

it('it formats correctly', async () => {
Expand All @@ -21,6 +23,12 @@ describe('ITSM formatter', () => {
it('it formats correctly when fields do not exist ', async () => {
const invalidFields = { connector: { fields: null } } as CaseResponse;
const res = await serviceNowITSMExternalServiceFormatter.format(invalidFields, []);
expect(res).toEqual({ severity: null, urgency: null, impact: null });
expect(res).toEqual({
severity: null,
urgency: null,
impact: null,
category: null,
subcategory: null,
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ export const choices = [
value: 'inbound_ddos',
element: 'subcategory',
},
{
dependent_value: '',
label: 'Software',
value: 'software',
element: 'category',
},
{
dependent_value: 'software',
label: 'Operation System',
value: 'os',
element: 'subcategory',
},
...['severity', 'urgency', 'impact', 'priority']
.map((element) => [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { EuiSelectOption } from '@elastic/eui';
import { Choice } from './types';

export const choicesToEuiOptions = (choices: Choice[]): EuiSelectOption[] =>
choices.map((choice) => ({ value: choice.value, text: choice.label }));
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ jest.mock('./use_get_choices', () => ({
}));

describe('ServiceNowITSM Fields', () => {
const fields = { severity: '1', urgency: '2', impact: '3' };
const fields = {
severity: '1',
urgency: '2',
impact: '3',
category: 'software',
subcategory: 'os',
};
const onChange = jest.fn();

beforeEach(() => {
Expand All @@ -37,6 +43,8 @@ describe('ServiceNowITSM Fields', () => {
expect(wrapper.find('[data-test-subj="severitySelect"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="urgencySelect"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="impactSelect"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="categorySelect"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="subcategorySelect"]').exists()).toBeTruthy();
});

it('all params fields are rendered - isEdit: false', () => {
Expand All @@ -58,6 +66,42 @@ describe('ServiceNowITSM Fields', () => {
);
});

test('it transforms the categories to options correctly', async () => {
const wrapper = mount(<Fields fields={fields} onChange={onChange} connector={connector} />);
act(() => {
onChoicesSuccess(mockChoices);
});

wrapper.update();
expect(wrapper.find('[data-test-subj="categorySelect"]').first().prop('options')).toEqual([
{ value: 'Priviledge Escalation', text: 'Priviledge Escalation' },
{
value: 'Criminal activity/investigation',
text: 'Criminal activity/investigation',
},
{ value: 'Denial of Service', text: 'Denial of Service' },
{
value: 'software',
text: 'Software',
},
]);
});

test('it transforms the subcategories to options correctly', async () => {
const wrapper = mount(<Fields fields={fields} onChange={onChange} connector={connector} />);
act(() => {
onChoicesSuccess(mockChoices);
});

wrapper.update();
expect(wrapper.find('[data-test-subj="subcategorySelect"]').first().prop('options')).toEqual([
{
text: 'Operation System',
value: 'os',
},
]);
});

it('it transforms the options correctly', async () => {
const wrapper = mount(<Fields fields={fields} onChange={onChange} connector={connector} />);
act(() => {
Expand All @@ -81,7 +125,7 @@ describe('ServiceNowITSM Fields', () => {

expect(onChange).toHaveBeenCalledWith(fields);

const testers = ['severity', 'urgency', 'impact'];
const testers = ['severity', 'urgency', 'impact', 'category', 'subcategory'];
testers.forEach((subj) =>
test(`${subj.toUpperCase()}`, async () => {
await waitFor(() => {
Expand Down
Loading

0 comments on commit d6bfcef

Please sign in to comment.