[Connector][TheHive] Show rule severity toggle and body jsoneditor in UI (#224669)

## Summary

- This PR unhides rule severity toggle and body jsoneditor in UI. (kept
hidden in PR : #207255 )
- Add functional test related to `createAlert` subaction.
- Remove unused variables from `translations.ts`.
- Remove the custom template description from documentation. 

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [x] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Brijesh Khunt 2025-06-24 14:23:46 +05:30 committed by GitHub
parent d34c993226
commit de031df3f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 153 additions and 42 deletions

View file

@ -93,7 +93,7 @@ Source reference
: A source reference for the alert.
Body
: A Json payload specifying additional parameter, such as observables and procedures. It can be populated using a predefined template or customized using the `Custom Template` option. For example:
: A Json payload specifying additional parameter, such as observables and procedures. For example:
```json
{

View file

@ -6,11 +6,12 @@
*/
import React from 'react';
import { render } from '@testing-library/react';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public/types';
import { TheHiveParamsAlertFields } from './params_alert';
import { SUB_ACTION } from '../../../common/thehive/constants';
import { ExecutorParams, ExecutorSubActionCreateAlertParams } from '../../../common/thehive/types';
import userEvent from '@testing-library/user-event';
describe('TheHiveParamsFields renders', () => {
const subActionParams: ExecutorSubActionCreateAlertParams = {
@ -61,12 +62,46 @@ describe('TheHiveParamsFields renders', () => {
expect(getByTestId('descriptionTextArea')).toBeInTheDocument();
expect(getByTestId('tagsInput')).toBeInTheDocument();
expect(getByTestId('severitySelectInput')).toBeInTheDocument();
expect(getByTestId('rule-severity-toggle')).toBeInTheDocument();
expect(getByTestId('tlpSelectInput')).toBeInTheDocument();
expect(getByTestId('typeInput')).toBeInTheDocument();
expect(getByTestId('sourceInput')).toBeInTheDocument();
expect(getByTestId('sourceRefInput')).toBeInTheDocument();
expect(getByTestId('bodyJsonEditor')).toBeInTheDocument();
expect(getByTestId('severitySelectInput')).toHaveValue('2');
expect(getByTestId('tlpSelectInput')).toHaveValue('2');
expect(getByTestId('rule-severity-toggle')).not.toBeChecked();
});
it('hides the severity select input when rule severity toggle is enabled', () => {
const { getByTestId } = render(<TheHiveParamsAlertFields {...defaultProps} />);
const ruleSeverityToggleEl = getByTestId('rule-severity-toggle');
fireEvent.click(ruleSeverityToggleEl);
expect(getByTestId('rule-severity-toggle')).toBeEnabled();
expect(editAction).toHaveBeenCalledWith(
'subActionParams',
{ ...subActionParams, severity: 2, isRuleSeverity: true },
0
);
expect(screen.queryByTestId('severitySelectInput')).not.toBeInTheDocument();
});
it('should updates body content', async () => {
const bodyValue = JSON.stringify({ bar: 'test' });
render(<TheHiveParamsAlertFields {...defaultProps} />);
await userEvent.click(await screen.findByTestId('bodyJsonEditor'));
await userEvent.paste(bodyValue);
await waitFor(() => {
expect(editAction).toHaveBeenCalledWith(
'subActionParams',
{ ...subActionParams, body: bodyValue },
0
);
});
});
});

View file

@ -154,7 +154,7 @@ export const TheHiveParamsAlertFields: React.FC<ActionParamsProps<ExecutorParams
}}
errors={errors['createAlertParam.sourceRef'] as string[]}
/>
{!isTest && Boolean(isRuleSeverity) && (
{!isTest && (
<EuiFormRow fullWidth>
<EuiSwitch
label={translations.IS_RULE_SEVERITY_LABEL}
@ -216,26 +216,24 @@ export const TheHiveParamsAlertFields: React.FC<ActionParamsProps<ExecutorParams
noSuggestions
/>
</EuiFormRow>
{alert.body != null && (
<JsonEditorWithMessageVariables
messageVariables={messageVariables}
paramsProperty={'body'}
inputTargetValue={alert.body}
label={translations.BODY_LABEL}
ariaLabel={translations.BODY_DESCRIPTION}
errors={errors.body as string[]}
onDocumentsChange={(json: string) =>
editAction('subActionParams', { ...alert, body: json }, index)
<JsonEditorWithMessageVariables
messageVariables={messageVariables}
paramsProperty={'body'}
inputTargetValue={alert.body}
label={translations.BODY_LABEL}
ariaLabel={translations.BODY_DESCRIPTION}
errors={errors.body as string[]}
onDocumentsChange={(json: string) =>
editAction('subActionParams', { ...alert, body: json }, index)
}
dataTestSubj="thehive-body"
onBlur={() => {
if (!alert.body) {
editAction('subActionParams', { ...alert, body: null }, index);
}
dataTestSubj="thehive-body"
onBlur={() => {
if (!alert.body) {
editAction('subActionParams', { ...alert, body: null }, index);
}
}}
isOptionalField
/>
)}
}}
isOptionalField
/>
</>
);
};

View file

@ -109,13 +109,6 @@ export const SOURCE_REF_LABEL = i18n.translate(
}
);
export const TEMPLATE_LABEL = i18n.translate(
'xpack.stackConnectors.components.thehive.templateFieldLabel',
{
defaultMessage: 'Template',
}
);
export const BODY_LABEL = i18n.translate(
'xpack.stackConnectors.components.thehive.bodyFieldLabel',
{
@ -130,13 +123,6 @@ export const BODY_DESCRIPTION = i18n.translate(
}
);
export const SELECT_BODY_TEMPLATE_POPOVER_BUTTON = i18n.translate(
'xpack.stackConnectors.components.thehive.selectBodyTemplatePopoverButton',
{
defaultMessage: 'Select body template',
}
);
export const TITLE_REQUIRED = i18n.translate(
'xpack.stackConnectors.components.thehive.requiredTitleText',
{

View file

@ -27,14 +27,17 @@ export class TheHiveSimulator extends Simulator {
if (this.returnError) {
return TheHiveSimulator.sendErrorResponse(response);
}
return TheHiveSimulator.sendResponse(response);
const pathName = request.url!;
return TheHiveSimulator.sendResponse(
response,
pathName.includes('case') ? theHiveCaseSuccessResponse : theHiveAlertSuccessResponse
);
}
private static sendResponse(response: http.ServerResponse) {
private static sendResponse(response: http.ServerResponse, data: any) {
response.statusCode = 201;
response.setHeader('Content-Type', 'application/json');
response.end(JSON.stringify(theHiveSuccessResponse, null, 4));
response.end(JSON.stringify(data, null, 4));
}
private static sendErrorResponse(response: http.ServerResponse) {
@ -44,7 +47,7 @@ export class TheHiveSimulator extends Simulator {
}
}
export const theHiveSuccessResponse = {
export const theHiveCaseSuccessResponse = {
_id: '~172064',
_type: 'Case',
_createdBy: 'user1@thehive.local',
@ -96,6 +99,34 @@ export const theHiveSuccessResponse = {
timeToDetect: 0,
};
export const theHiveAlertSuccessResponse = {
_id: '~245821592',
_type: 'Alert',
_createdBy: 'user1@thehive.local',
_createdAt: 1750411773815,
type: 'type',
source: 'source',
sourceRef: 'sourceRef',
title: 'title',
description: 'description',
severity: 1,
severityLabel: 'LOW',
date: 1750411773798,
tags: ['tags1', 'tags2'],
tlp: 2,
tlpLabel: 'AMBER',
pap: 2,
papLabel: 'AMBER',
follow: true,
customFields: [],
observableCount: 3,
status: 'New',
stage: 'New',
extraData: {},
newDate: 1750411773800,
timeToDetect: 0,
};
export const theHiveFailedResponse = {
type: 'BadRequest',
message: 'Invalid json',

View file

@ -244,7 +244,7 @@ export default function theHiveTest({ getService }: FtrProviderContext) {
simulator.close();
});
it('should send a formatted JSON object', async () => {
it('should create a case', async () => {
const { body } = await supertest
.post(`/api/actions/connector/${theHiveActionId}/_execute`)
.set('kbn-xsrf', 'foo')
@ -284,6 +284,67 @@ export default function theHiveTest({ getService }: FtrProviderContext) {
},
});
});
it('should create an alert', async () => {
const { body } = await supertest
.post(`/api/actions/connector/${theHiveActionId}/_execute`)
.set('kbn-xsrf', 'foo')
.send({
params: {
subAction: 'createAlert',
subActionParams: {
title: 'title',
description: 'description',
tlp: 2,
source: 'source',
type: 'type',
sourceRef: 'sourceRef',
isRuleSeverity: false,
severity: 1,
tags: ['tags1', 'tags2'],
body: '{"observables":[{"dataType":"url","data":"http://example.com"},{"dataType":"mail","data":"foo@example.org"},{"dataType":"ip","data":"127.0.0.1"}],"procedures":[{"patternId":"T1132","occurDate":1640000000000}]}',
},
},
})
.expect(200);
expect(simulator.requestData).to.eql({
title: 'title',
description: 'description',
type: 'type',
source: 'source',
sourceRef: 'sourceRef',
severity: 1,
tags: ['tags1', 'tags2'],
tlp: 2,
observables: [
{
dataType: 'url',
data: 'http://example.com',
},
{
dataType: 'mail',
data: 'foo@example.org',
},
{
dataType: 'ip',
data: '127.0.0.1',
},
],
procedures: [
{
patternId: 'T1132',
occurDate: 1640000000000,
},
],
});
expect(body).to.eql({
status: 'ok',
connector_id: theHiveActionId,
data: {},
});
});
});
describe('error response simulator', () => {