mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Security Solution] [Exceptions] Adds options to create a shared exception list and to create a single item from the manage exceptions view (#144575)
Adds options to create a shared exception list and creating a single item to be attached to multiple rules default lists or to add it to shared lists. Co-authored-by: Gloria Hornero <gloria.hornero@elastic.co> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
9298023c1b
commit
b1179e72ff
11 changed files with 481 additions and 7 deletions
|
@ -8,6 +8,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import { EuiComboBox } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { FieldProps } from './types';
|
||||
import { useField } from './use_field';
|
||||
|
@ -62,7 +63,10 @@ export const FieldComponent: React.FC<FieldProps> = ({
|
|||
data-test-subj="fieldAutocompleteComboBox"
|
||||
style={fieldWidth}
|
||||
onCreateOption={handleCreateCustomOption}
|
||||
customOptionText="Add {searchValue} as your occupation"
|
||||
customOptionText={i18n.translate('autocomplete.customOptionText', {
|
||||
defaultMessage: 'Add {searchValuePlaceholder} as a custom field',
|
||||
values: { searchValuePlaceholder: '{searchValue}' },
|
||||
})}
|
||||
fullWidth
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -21,8 +21,8 @@ export const exceptionListTypeOrUndefined = t.union([exceptionListType, t.undefi
|
|||
export type ExceptionListType = t.TypeOf<typeof exceptionListType>;
|
||||
export type ExceptionListTypeOrUndefined = t.TypeOf<typeof exceptionListTypeOrUndefined>;
|
||||
export enum ExceptionListTypeEnum {
|
||||
DETECTION = 'detection',
|
||||
RULE_DEFAULT = 'rule_default',
|
||||
DETECTION = 'detection', // shared exception list type
|
||||
RULE_DEFAULT = 'rule_default', // rule default, cannot be shared
|
||||
ENDPOINT = 'endpoint',
|
||||
ENDPOINT_TRUSTED_APPS = 'endpoint',
|
||||
ENDPOINT_EVENTS = 'endpoint_events',
|
||||
|
|
|
@ -256,6 +256,12 @@ export const LEGACY_NOTIFICATIONS_ID = `siem.notifications` as const;
|
|||
*/
|
||||
export const UPDATE_OR_CREATE_LEGACY_ACTIONS = '/internal/api/detection/legacy/notifications';
|
||||
|
||||
/**
|
||||
* Exceptions management routes
|
||||
*/
|
||||
|
||||
export const SHARED_EXCEPTION_LIST_URL = `/api${EXCEPTIONS_PATH}/shared` as const;
|
||||
|
||||
/**
|
||||
* Detection engine routes
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* 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 type { ChangeEvent } from 'react';
|
||||
import React, { memo, useState, useCallback, useRef, useEffect } from 'react';
|
||||
import {
|
||||
EuiFlyout,
|
||||
EuiTitle,
|
||||
EuiFlyoutHeader,
|
||||
EuiFlyoutBody,
|
||||
EuiText,
|
||||
EuiFieldText,
|
||||
EuiSpacer,
|
||||
EuiTextArea,
|
||||
EuiFlyoutFooter,
|
||||
EuiFlexGroup,
|
||||
EuiButtonEmpty,
|
||||
EuiButton,
|
||||
EuiFlexItem,
|
||||
} from '@elastic/eui';
|
||||
import type { HttpSetup } from '@kbn/core-http-browser';
|
||||
import type { ErrorToastOptions, Toast, ToastInput } from '@kbn/core-notifications-browser';
|
||||
import { i18n as translate } from '@kbn/i18n';
|
||||
import type { ListDetails } from '@kbn/securitysolution-exception-list-components';
|
||||
|
||||
import { useCreateSharedExceptionListWithOptionalSignal } from './use_create_shared_list';
|
||||
import {
|
||||
CREATE_SHARED_LIST_TITLE,
|
||||
CREATE_SHARED_LIST_NAME_FIELD,
|
||||
CREATE_SHARED_LIST_DESCRIPTION,
|
||||
CREATE_BUTTON,
|
||||
CLOSE_FLYOUT,
|
||||
CREATE_SHARED_LIST_DESCRIPTION_PLACEHOLDER,
|
||||
CREATE_SHARED_LIST_NAME_FIELD_PLACEHOLDER,
|
||||
SUCCESS_TITLE,
|
||||
getSuccessText,
|
||||
} from './translations';
|
||||
|
||||
export const CreateSharedListFlyout = memo(
|
||||
({
|
||||
handleRefresh,
|
||||
http,
|
||||
handleCloseFlyout,
|
||||
addSuccess,
|
||||
addError,
|
||||
}: {
|
||||
handleRefresh: () => void;
|
||||
http: HttpSetup;
|
||||
addSuccess: (toastOrTitle: ToastInput, options?: unknown) => Toast;
|
||||
addError: (error: unknown, options: ErrorToastOptions) => Toast;
|
||||
handleCloseFlyout: () => void;
|
||||
}) => {
|
||||
const { start: createSharedExceptionList, ...createSharedExceptionListState } =
|
||||
useCreateSharedExceptionListWithOptionalSignal();
|
||||
const ctrl = useRef(new AbortController());
|
||||
|
||||
enum DetailProperty {
|
||||
name = 'name',
|
||||
description = 'description',
|
||||
}
|
||||
|
||||
const [newListDetails, setNewListDetails] = useState<ListDetails>({
|
||||
name: '',
|
||||
description: '',
|
||||
});
|
||||
const onChange = (
|
||||
{ target }: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
detailProperty: DetailProperty.name | DetailProperty.description
|
||||
) => {
|
||||
const { value } = target;
|
||||
setNewListDetails({ ...newListDetails, [detailProperty]: value });
|
||||
};
|
||||
|
||||
const handleCreateSharedExceptionList = useCallback(() => {
|
||||
if (!createSharedExceptionListState.loading && newListDetails.name !== '') {
|
||||
ctrl.current = new AbortController();
|
||||
|
||||
createSharedExceptionList({
|
||||
http,
|
||||
signal: ctrl.current.signal,
|
||||
name: newListDetails.name,
|
||||
description: newListDetails.description ?? '',
|
||||
});
|
||||
}
|
||||
}, [createSharedExceptionList, createSharedExceptionListState.loading, newListDetails, http]);
|
||||
|
||||
const handleCreateSuccess = useCallback(
|
||||
(response) => {
|
||||
addSuccess({
|
||||
text: getSuccessText(newListDetails.name),
|
||||
title: SUCCESS_TITLE,
|
||||
});
|
||||
handleRefresh();
|
||||
|
||||
handleCloseFlyout();
|
||||
},
|
||||
[addSuccess, handleCloseFlyout, handleRefresh, newListDetails]
|
||||
);
|
||||
|
||||
const handleCreateError = useCallback(
|
||||
(error) => {
|
||||
if (!error.message.includes('AbortError') && !error?.body?.message.includes('AbortError')) {
|
||||
addError(error, {
|
||||
title: translate.translate(
|
||||
'xpack.securitySolution.exceptions.createSharedExceptionListErrorTitle',
|
||||
{
|
||||
defaultMessage: 'creation error',
|
||||
}
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
[addError]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!createSharedExceptionListState.loading) {
|
||||
if (createSharedExceptionListState?.result) {
|
||||
handleCreateSuccess(createSharedExceptionListState.result);
|
||||
} else if (createSharedExceptionListState?.error) {
|
||||
handleCreateError(createSharedExceptionListState?.error);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
createSharedExceptionListState?.error,
|
||||
createSharedExceptionListState.loading,
|
||||
createSharedExceptionListState.result,
|
||||
handleCreateError,
|
||||
handleCreateSuccess,
|
||||
]);
|
||||
|
||||
return (
|
||||
<EuiFlyout
|
||||
ownFocus
|
||||
size="s"
|
||||
onClose={handleCloseFlyout}
|
||||
data-test-subj="createSharedExceptionListFlyout"
|
||||
>
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
<EuiTitle size="m">
|
||||
<h2 data-test-subj="createSharedExceptionListTitle">{CREATE_SHARED_LIST_TITLE}</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlyoutHeader>
|
||||
<EuiFlyoutBody>
|
||||
<EuiText>{CREATE_SHARED_LIST_NAME_FIELD}</EuiText>
|
||||
<EuiFieldText
|
||||
placeholder={CREATE_SHARED_LIST_NAME_FIELD_PLACEHOLDER}
|
||||
value={newListDetails.name}
|
||||
onChange={(e) => onChange(e, DetailProperty.name)}
|
||||
aria-label="Use aria labels when no actual label is in use"
|
||||
/>
|
||||
<EuiSpacer />
|
||||
<EuiText>{CREATE_SHARED_LIST_DESCRIPTION}</EuiText>
|
||||
<EuiTextArea
|
||||
placeholder={CREATE_SHARED_LIST_DESCRIPTION_PLACEHOLDER}
|
||||
value={newListDetails.description}
|
||||
onChange={(e) => onChange(e, DetailProperty.description)}
|
||||
aria-label="Stop the hackers"
|
||||
/>
|
||||
</EuiFlyoutBody>
|
||||
<EuiFlyoutFooter>
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty iconType="cross" onClick={handleCloseFlyout} flush="left">
|
||||
{CLOSE_FLYOUT}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
data-test-subj="exception-lists-form-create-shared"
|
||||
onClick={handleCreateSharedExceptionList}
|
||||
disabled={newListDetails.name === ''}
|
||||
>
|
||||
{CREATE_BUTTON}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlyoutFooter>
|
||||
</EuiFlyout>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
CreateSharedListFlyout.displayName = 'CreateSharedListFlyout';
|
|
@ -46,6 +46,9 @@ import { ALL_ENDPOINT_ARTIFACT_LIST_IDS } from '../../../common/endpoint/service
|
|||
import { ExceptionsListCard } from './exceptions_list_card';
|
||||
|
||||
import { ImportExceptionListFlyout } from './import_exceptions_list_flyout';
|
||||
import { CreateSharedListFlyout } from './create_shared_exception_list';
|
||||
|
||||
import { AddExceptionFlyout } from '../../detection_engine/rule_exceptions/components/add_exception_flyout';
|
||||
|
||||
export type Func = () => Promise<void>;
|
||||
|
||||
|
@ -355,6 +358,16 @@ export const ExceptionListsTable = React.memo(() => {
|
|||
|
||||
const goToPage = (pageNumber: number) => setActivePage(pageNumber);
|
||||
|
||||
const [isCreatePopoverOpen, setIsCreatePopoverOpen] = useState(false);
|
||||
const [displayAddExceptionItemFlyout, setDisplayAddExceptionItemFlyout] = useState(false);
|
||||
const [displayCreateSharedListFlyout, setDisplayCreateSharedListFlyout] = useState(false);
|
||||
|
||||
const onCreateButtonClick = () => setIsCreatePopoverOpen((isOpen) => !isOpen);
|
||||
const onCloseCreatePopover = () => {
|
||||
setDisplayAddExceptionItemFlyout(false);
|
||||
setIsCreatePopoverOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<MissingPrivilegesCallOut />
|
||||
|
@ -370,11 +383,67 @@ export const ExceptionListsTable = React.memo(() => {
|
|||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton iconType={'importAction'} onClick={() => setDisplayImportListFlyout(true)}>
|
||||
{i18n.IMPORT_EXCEPTION_LIST}
|
||||
{i18n.IMPORT_EXCEPTION_LIST_BUTTON}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiPopover
|
||||
data-test-subj="manageExceptionListCreateButton"
|
||||
button={
|
||||
<EuiButton iconType={'arrowDown'} onClick={onCreateButtonClick}>
|
||||
{i18n.CREATE_BUTTON}
|
||||
</EuiButton>
|
||||
}
|
||||
isOpen={isCreatePopoverOpen}
|
||||
closePopover={onCloseCreatePopover}
|
||||
>
|
||||
<EuiContextMenuPanel
|
||||
items={[
|
||||
<EuiContextMenuItem
|
||||
key={'createList'}
|
||||
onClick={() => {
|
||||
onCloseCreatePopover();
|
||||
setDisplayCreateSharedListFlyout(true);
|
||||
}}
|
||||
>
|
||||
{i18n.CREATE_SHARED_LIST_BUTTON}
|
||||
</EuiContextMenuItem>,
|
||||
<EuiContextMenuItem
|
||||
key={'createItem'}
|
||||
onClick={() => {
|
||||
onCloseCreatePopover();
|
||||
setDisplayAddExceptionItemFlyout(true);
|
||||
}}
|
||||
>
|
||||
{i18n.CREATE_BUTTON_ITEM_BUTTON}
|
||||
</EuiContextMenuItem>,
|
||||
]}
|
||||
/>
|
||||
</EuiPopover>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
{displayCreateSharedListFlyout && (
|
||||
<CreateSharedListFlyout
|
||||
handleRefresh={handleRefresh}
|
||||
http={http}
|
||||
addSuccess={addSuccess}
|
||||
addError={addError}
|
||||
handleCloseFlyout={() => setDisplayCreateSharedListFlyout(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{displayAddExceptionItemFlyout && (
|
||||
<AddExceptionFlyout
|
||||
rules={null}
|
||||
isEndpointItem={false}
|
||||
isBulkAction={false}
|
||||
showAlertCloseOptions
|
||||
onCancel={(didRuleChange: boolean) => setDisplayAddExceptionItemFlyout(false)}
|
||||
onConfirm={(didRuleChange: boolean) => setDisplayAddExceptionItemFlyout(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{displayImportListFlyout && (
|
||||
<ImportExceptionListFlyout
|
||||
handleRefresh={handleRefresh}
|
||||
|
|
|
@ -36,7 +36,7 @@ export const EXPORT_EXCEPTION_LIST = i18n.translate(
|
|||
);
|
||||
|
||||
export const IMPORT_EXCEPTION_LIST_HEADER = i18n.translate(
|
||||
'xpack.securitySolution.exceptionsTable.importExceptionListFlyoutHeader',
|
||||
'xpack.securitySolution.exceptionsTable.importExceptionListHeader',
|
||||
{
|
||||
defaultMessage: 'Import shared exception list',
|
||||
}
|
||||
|
@ -104,3 +104,58 @@ export const IMPORT_PROMPT = i18n.translate(
|
|||
defaultMessage: 'Select or drag and drop multiple files',
|
||||
}
|
||||
);
|
||||
|
||||
export const CREATE_SHARED_LIST_TITLE = i18n.translate(
|
||||
'xpack.securitySolution.exceptions.createSharedExceptionListTitle',
|
||||
{
|
||||
defaultMessage: 'Create shared exception list',
|
||||
}
|
||||
);
|
||||
|
||||
export const CREATE_SHARED_LIST_NAME_FIELD = i18n.translate(
|
||||
'xpack.securitySolution.exceptions.createSharedExceptionListFlyoutNameField',
|
||||
{
|
||||
defaultMessage: 'Shared exception list name',
|
||||
}
|
||||
);
|
||||
|
||||
export const CREATE_SHARED_LIST_NAME_FIELD_PLACEHOLDER = i18n.translate(
|
||||
'xpack.securitySolution.exceptions.createSharedExceptionListFlyoutNameFieldPlaceholder',
|
||||
{
|
||||
defaultMessage: 'New exception list',
|
||||
}
|
||||
);
|
||||
|
||||
export const CREATE_SHARED_LIST_DESCRIPTION = i18n.translate(
|
||||
'xpack.securitySolution.exceptions.createSharedExceptionListFlyoutDescription',
|
||||
{
|
||||
defaultMessage: 'Description (optional)',
|
||||
}
|
||||
);
|
||||
|
||||
export const CREATE_SHARED_LIST_DESCRIPTION_PLACEHOLDER = i18n.translate(
|
||||
'xpack.securitySolution.exceptions.createSharedExceptionListFlyoutDescriptionPlaceholder',
|
||||
{
|
||||
defaultMessage: 'New exception list',
|
||||
}
|
||||
);
|
||||
|
||||
export const CREATE_BUTTON = i18n.translate(
|
||||
'xpack.securitySolution.exceptions.createSharedExceptionListFlyoutCreateButton',
|
||||
{
|
||||
defaultMessage: 'Create shared exception list',
|
||||
}
|
||||
);
|
||||
|
||||
export const getSuccessText = (listName: string) =>
|
||||
i18n.translate('xpack.securitySolution.exceptions.createSharedExceptionListSuccessDescription', {
|
||||
defaultMessage: 'list with name ${listName} was created!',
|
||||
values: { listName },
|
||||
});
|
||||
|
||||
export const SUCCESS_TITLE = i18n.translate(
|
||||
'xpack.securitySolution.exceptions.createSharedExceptionListSuccessTitle',
|
||||
{
|
||||
defaultMessage: 'created list',
|
||||
}
|
||||
);
|
||||
|
|
|
@ -195,9 +195,30 @@ export const UPLOAD_ERROR = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
export const IMPORT_EXCEPTION_LIST = i18n.translate(
|
||||
'xpack.securitySolution.lists.importExceptionListButton',
|
||||
export const IMPORT_EXCEPTION_LIST_BUTTON = i18n.translate(
|
||||
'xpack.securitySolution.exceptions.manageExceptions.importExceptionList',
|
||||
{
|
||||
defaultMessage: 'Import exception list',
|
||||
}
|
||||
);
|
||||
|
||||
export const CREATE_BUTTON = i18n.translate(
|
||||
'xpack.securitySolution.exceptions.manageExceptions.create',
|
||||
{
|
||||
defaultMessage: 'Create',
|
||||
}
|
||||
);
|
||||
|
||||
export const CREATE_SHARED_LIST_BUTTON = i18n.translate(
|
||||
'xpack.securitySolution.exceptions.manageExceptions.createSharedListButton',
|
||||
{
|
||||
defaultMessage: 'create shared list',
|
||||
}
|
||||
);
|
||||
|
||||
export const CREATE_BUTTON_ITEM_BUTTON = i18n.translate(
|
||||
'xpack.securitySolution.exceptions.manageExceptions.createItemButton',
|
||||
{
|
||||
defaultMessage: 'create exception item',
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types';
|
||||
|
||||
import type { HttpStart } from '@kbn/core/public';
|
||||
import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils';
|
||||
|
||||
import { SHARED_EXCEPTION_LIST_URL } from '../../../common/constants';
|
||||
|
||||
export const createSharedExceptionList = async ({
|
||||
name,
|
||||
description,
|
||||
http,
|
||||
signal,
|
||||
}: {
|
||||
http: HttpStart;
|
||||
signal: AbortSignal;
|
||||
name: string;
|
||||
description: string;
|
||||
}): Promise<ExceptionListSchema> => {
|
||||
const res: ExceptionListSchema = await http.post<ExceptionListSchema>(SHARED_EXCEPTION_LIST_URL, {
|
||||
body: JSON.stringify({ name, description }),
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
method: 'POST',
|
||||
signal,
|
||||
});
|
||||
return res;
|
||||
};
|
||||
|
||||
const createSharedExceptionListWithOptionalSignal = withOptionalSignal(createSharedExceptionList);
|
||||
|
||||
export const useCreateSharedExceptionListWithOptionalSignal = () =>
|
||||
useAsync(createSharedExceptionListWithOptionalSignal);
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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 * as t from 'io-ts';
|
||||
import uuid from 'uuid';
|
||||
|
||||
import { SHARED_EXCEPTION_LIST_URL } from '../../../../../common/constants';
|
||||
import type { SecuritySolutionPluginRouter } from '../../../../types';
|
||||
import { buildSiemResponse } from '../../../detection_engine/routes/utils';
|
||||
import { buildRouteValidation } from '../../../../utils/build_validation/route_validation';
|
||||
|
||||
/**
|
||||
* URL path parameters of the API route.
|
||||
*/
|
||||
export const CreateSharedExceptionListRequestParams = t.exact(
|
||||
t.type({
|
||||
name: t.string,
|
||||
description: t.string,
|
||||
})
|
||||
);
|
||||
export type CreateSharedExceptionListRequestParams = t.TypeOf<
|
||||
typeof CreateSharedExceptionListRequestParams
|
||||
>;
|
||||
|
||||
export type CreateSharedExceptionListRequestParamsDecoded = CreateSharedExceptionListRequestParams;
|
||||
|
||||
export const createSharedExceptionListRoute = (router: SecuritySolutionPluginRouter) => {
|
||||
router.post(
|
||||
{
|
||||
path: SHARED_EXCEPTION_LIST_URL,
|
||||
validate: {
|
||||
body: buildRouteValidation<
|
||||
typeof CreateSharedExceptionListRequestParams,
|
||||
CreateSharedExceptionListRequestParams
|
||||
>(CreateSharedExceptionListRequestParams),
|
||||
},
|
||||
options: {
|
||||
tags: ['access:securitySolution'],
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const siemResponse = buildSiemResponse(response);
|
||||
const { description, name } = request.body;
|
||||
|
||||
try {
|
||||
const ctx = await context.resolve([
|
||||
'core',
|
||||
'securitySolution',
|
||||
'alerting',
|
||||
'licensing',
|
||||
'lists',
|
||||
]);
|
||||
const listsClient = ctx.securitySolution.getExceptionListClient();
|
||||
const createdSharedList = await listsClient?.createExceptionList({
|
||||
description,
|
||||
immutable: false,
|
||||
listId: uuid.v4(),
|
||||
meta: undefined,
|
||||
name,
|
||||
namespaceType: 'agnostic',
|
||||
tags: [],
|
||||
type: 'detection',
|
||||
version: 1,
|
||||
});
|
||||
return response.ok({ body: createdSharedList });
|
||||
} catch (exc) {
|
||||
return siemResponse.error({
|
||||
body: exc.message,
|
||||
statusCode: 404,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
|
@ -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.
|
||||
*/
|
||||
|
||||
import type { SecuritySolutionPluginRouter } from '../../../types';
|
||||
|
||||
import { createSharedExceptionListRoute } from './manage_exceptions/route';
|
||||
|
||||
export const registerManageExceptionsRoutes = (router: SecuritySolutionPluginRouter) => {
|
||||
createSharedExceptionListRoute(router);
|
||||
};
|
|
@ -71,6 +71,7 @@ import {
|
|||
installRiskScoresRoute,
|
||||
readPrebuiltDevToolContentRoute,
|
||||
} from '../lib/risk_score/routes';
|
||||
import { registerManageExceptionsRoutes } from '../lib/exceptions/api/register_routes';
|
||||
|
||||
export const initRoutes = (
|
||||
router: SecuritySolutionPluginRouter,
|
||||
|
@ -92,6 +93,7 @@ export const initRoutes = (
|
|||
registerLegacyRuleActionsRoutes(router, logger);
|
||||
registerPrebuiltRulesRoutes(router, config, security);
|
||||
registerRuleExceptionsRoutes(router);
|
||||
registerManageExceptionsRoutes(router);
|
||||
registerRuleManagementRoutes(router, config, ml, logger);
|
||||
registerRuleMonitoringRoutes(router);
|
||||
registerRulePreviewRoutes(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue