-
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
TheHive Connector for Cases #180931
TheHive Connector for Cases #180931
Changes from 5 commits
6ddf8c5
48938ec
a98d141
19b81b2
1ea1945
c5ba79a
c58a578
db3d840
6d0dea7
1aa9649
c8e1aea
ac4f754
bf5598d
63b8bd6
0b5da8a
f7c3aa6
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,50 @@ | ||
/* | ||
* 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 React from 'react'; | ||
import userEvent from '@testing-library/user-event'; | ||
import { screen } from '@testing-library/react'; | ||
import Fields from './case_fields'; | ||
import { theHiveConnector as connector } from '../mock'; | ||
import { MockFormWrapperComponent } from '../test_utils'; | ||
import type { AppMockRenderer } from '../../../common/mock'; | ||
import { createAppMockRenderer } from '../../../common/mock'; | ||
import { TheHiveTLP } from './types'; | ||
|
||
describe('TheHive Cases Fields', () => { | ||
const fields = { | ||
TLP: '1', | ||
}; | ||
|
||
let appMockRenderer: AppMockRenderer; | ||
|
||
beforeEach(() => { | ||
appMockRenderer = createAppMockRenderer(); | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('all params fields are rendered', () => { | ||
appMockRenderer.render( | ||
<MockFormWrapperComponent fields={fields}> | ||
<Fields connector={connector} /> | ||
</MockFormWrapperComponent> | ||
); | ||
|
||
expect(screen.getByText('TLP')).toBeInTheDocument(); | ||
}); | ||
|
||
it('sets TLP correctly', async () => { | ||
appMockRenderer.render( | ||
<MockFormWrapperComponent fields={fields}> | ||
<Fields connector={connector} /> | ||
</MockFormWrapperComponent> | ||
); | ||
|
||
userEvent.selectOptions(screen.getByTestId('tlp-field'), '4'); | ||
expect(await screen.findByTestId('tlp-field')).toHaveValue(TheHiveTLP.RED); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* 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 React from 'react'; | ||
import { SelectField } from '@kbn/es-ui-shared-plugin/static/forms/components'; | ||
import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; | ||
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; | ||
import type { ConnectorFieldsProps } from '../types'; | ||
import * as i18n from './translations'; | ||
import { TheHiveTLP } from './types'; | ||
|
||
const { emptyField } = fieldValidators; | ||
|
||
const tlpOptions: Array<{ text: string; value: string }> = [ | ||
{ | ||
text: 'CLEAR', | ||
value: TheHiveTLP.CLEAR, | ||
}, | ||
{ | ||
text: 'GREEN', | ||
value: TheHiveTLP.GREEN, | ||
}, | ||
{ | ||
text: 'AMBER', | ||
value: TheHiveTLP.AMBER, | ||
}, | ||
{ | ||
text: 'AMBER+STRICT', | ||
value: TheHiveTLP.AMBER_STRICT, | ||
}, | ||
{ | ||
text: 'RED', | ||
value: TheHiveTLP.RED, | ||
}, | ||
]; | ||
|
||
const TheHiveFieldsComponent: React.FunctionComponent<ConnectorFieldsProps> = () => { | ||
return ( | ||
<div data-test-subj={'connector-fields-Thehive'}> | ||
<UseField | ||
path="fields.tlp" | ||
component={SelectField} | ||
config={{ | ||
label: i18n.TLP_LABEL, | ||
validations: [ | ||
{ | ||
validator: emptyField(i18n.TLP_REQUIRED), | ||
}, | ||
], | ||
}} | ||
componentProps={{ | ||
euiFieldProps: { | ||
'data-test-subj': 'tlp-field', | ||
options: tlpOptions, | ||
fullWidth: true, | ||
hasNoInitialSelection: true, | ||
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. Given that the field is required should we have a default value on the dropdown? 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. Yes, |
||
}, | ||
}} | ||
/> | ||
</div> | ||
); | ||
}; | ||
|
||
TheHiveFieldsComponent.displayName = 'ThehiveFields'; | ||
|
||
// eslint-disable-next-line import/no-default-export | ||
export { TheHiveFieldsComponent as default }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* 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 React from 'react'; | ||
import { screen } from '@testing-library/react'; | ||
import FieldsPreview from './case_fields_preview'; | ||
import type { AppMockRenderer } from '../../../common/mock'; | ||
import { theHiveConnector } from '../mock'; | ||
import { createAppMockRenderer } from '../../../common/mock'; | ||
import { createQueryWithMarkup } from '../../../common/test_utils'; | ||
|
||
describe('TheHive Fields: Preview', () => { | ||
const fields = { | ||
tlp: '1', | ||
}; | ||
|
||
let appMockRenderer: AppMockRenderer; | ||
|
||
beforeEach(() => { | ||
appMockRenderer = createAppMockRenderer(); | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('renders all fields correctly', () => { | ||
appMockRenderer.render(<FieldsPreview connector={theHiveConnector} fields={fields} />); | ||
|
||
const getByText = createQueryWithMarkup(screen.getByText); | ||
expect(getByText('TLP: GREEN')).toBeInTheDocument(); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* 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 React, { useMemo } from 'react'; | ||
|
||
import type { TheHiveFieldsType } from '../../../../common/types/domain'; | ||
import { ConnectorTypes } from '../../../../common/types/domain'; | ||
import type { ConnectorFieldsPreviewProps } from '../types'; | ||
import { ConnectorCard } from '../card'; | ||
import * as i18n from './translations'; | ||
|
||
const mapTLP = (tlpValue: number | string): string => { | ||
switch (tlpValue) { | ||
case '0': | ||
return 'CLEAR'; | ||
case '1': | ||
return 'GREEN'; | ||
case '2': | ||
return 'AMBER'; | ||
case '3': | ||
return 'AMBER+STRICT'; | ||
case '4': | ||
return 'RED'; | ||
default: | ||
return 'AMBER'; | ||
} | ||
}; | ||
|
||
const TheHiveFieldsPreviewComponent: React.FunctionComponent< | ||
ConnectorFieldsPreviewProps<TheHiveFieldsType> | ||
> = ({ fields, connector }) => { | ||
const { tlp } = fields ?? {}; | ||
|
||
const listItems = useMemo( | ||
() => [ | ||
...(tlp !== null | ||
? [ | ||
{ | ||
title: i18n.TLP_LABEL, | ||
description: mapTLP(tlp), | ||
}, | ||
] | ||
: []), | ||
], | ||
[tlp] | ||
); | ||
|
||
return ( | ||
<ConnectorCard | ||
connectorType={ConnectorTypes.theHive} | ||
isLoading={false} | ||
listItems={listItems} | ||
title={connector.name} | ||
/> | ||
); | ||
}; | ||
|
||
TheHiveFieldsPreviewComponent.displayName = 'TheHiveFieldsPreview'; | ||
|
||
// eslint-disable-next-line import/no-default-export | ||
export { TheHiveFieldsPreviewComponent as default }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
* 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 { lazy } from 'react'; | ||
|
||
import type { CaseConnector } from '../types'; | ||
import type { TheHiveFieldsType } from '../../../../common/types/domain'; | ||
import { ConnectorTypes } from '../../../../common/types/domain'; | ||
|
||
export * from './types'; | ||
|
||
export const getCaseConnector = (): CaseConnector<TheHiveFieldsType> => ({ | ||
id: ConnectorTypes.theHive, | ||
fieldsComponent: lazy(() => import('./case_fields')), | ||
previewComponent: lazy(() => import('./case_fields_preview')), | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* | ||
* 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 { i18n } from '@kbn/i18n'; | ||
|
||
|
||
export const TLP_LABEL = i18n.translate( | ||
'xpack.cases.connectors.thehive.tlpLable', | ||
{ | ||
defaultMessage: 'TLP', | ||
} | ||
); | ||
|
||
export const TLP_REQUIRED = i18n.translate( | ||
'xpack.cases.connectors.thehive.tlpLableRequired', | ||
{ | ||
defaultMessage: 'TLP is required', | ||
} | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
export enum TheHiveTLP { | ||
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. I think is better if we do
The reason is that by doing
we rely on the order of the enum ( 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. Yes, That make more sense. Let me change it. |
||
CLEAR = "0", | ||
GREEN = "1", | ||
AMBER = "2", | ||
AMBER_STRICT = "3", | ||
RED = "4" | ||
} |
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.
The schema of the
tlp
of the connector isnumber
and not a string. I think we should keep the same convention here for cases (number
ornull
). This way we can avoid doingparseInt(tlp, 10)
on the backend. We may need to do it on the frontend as theselect
dropdown accepts only strings as values (as you do herex-pack/plugins/stack_connectors/public/connector_types/thehive/params_case.tsx
).