mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Security Solution] Exceptions TTL Follow-up (#151952)
This commit is contained in:
parent
d7bd1d210b
commit
203fa3a955
21 changed files with 249 additions and 64 deletions
|
@ -22,7 +22,6 @@ import { description } from '../../common/description';
|
|||
import { name } from '../../common/name';
|
||||
import { meta } from '../../common/meta';
|
||||
import { tags } from '../../common/tags';
|
||||
import { ExpireTimeOrUndefined, expireTimeOrUndefined } from '../../common';
|
||||
|
||||
export const createEndpointListItemSchema = t.intersection([
|
||||
t.exact(
|
||||
|
@ -40,7 +39,6 @@ export const createEndpointListItemSchema = t.intersection([
|
|||
meta, // defaults to undefined if not set during decode
|
||||
os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode
|
||||
tags, // defaults to empty array if not set during decode
|
||||
expire_time: expireTimeOrUndefined, // defaults to undefined if not set during decode
|
||||
})
|
||||
),
|
||||
]);
|
||||
|
@ -50,12 +48,11 @@ export type CreateEndpointListItemSchema = t.OutputOf<typeof createEndpointListI
|
|||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type CreateEndpointListItemSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof createEndpointListItemSchema>>,
|
||||
'tags' | 'item_id' | 'entries' | 'comments' | 'os_types' | 'expire_time'
|
||||
'tags' | 'item_id' | 'entries' | 'comments' | 'os_types'
|
||||
> & {
|
||||
comments: CreateCommentsArray;
|
||||
tags: Tags;
|
||||
item_id: ItemId;
|
||||
entries: EntriesArray;
|
||||
os_types: OsTypeArray;
|
||||
expire_time: ExpireTimeOrUndefined;
|
||||
};
|
||||
|
|
|
@ -21,7 +21,6 @@ import { Tags, tags } from '../../common/tags';
|
|||
import { RequiredKeepUndefined } from '../../common/required_keep_undefined';
|
||||
import { UpdateCommentsArray } from '../../common/update_comment';
|
||||
import { EntriesArray } from '../../common/entries';
|
||||
import { ExpireTimeOrUndefined, expireTimeOrUndefined } from '../../common';
|
||||
|
||||
export const updateEndpointListItemSchema = t.intersection([
|
||||
t.exact(
|
||||
|
@ -41,7 +40,6 @@ export const updateEndpointListItemSchema = t.intersection([
|
|||
meta, // defaults to undefined if not set during decode
|
||||
os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode
|
||||
tags, // defaults to empty array if not set during decode
|
||||
expire_time: expireTimeOrUndefined,
|
||||
})
|
||||
),
|
||||
]);
|
||||
|
@ -51,11 +49,10 @@ export type UpdateEndpointListItemSchema = t.OutputOf<typeof updateEndpointListI
|
|||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type UpdateEndpointListItemSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof updateEndpointListItemSchema>>,
|
||||
'tags' | 'entries' | 'comments' | 'expire_time'
|
||||
'tags' | 'entries' | 'comments'
|
||||
> & {
|
||||
comments: UpdateCommentsArray;
|
||||
tags: Tags;
|
||||
entries: EntriesArray;
|
||||
os_types: OsTypeArray;
|
||||
expire_time: ExpireTimeOrUndefined;
|
||||
};
|
||||
|
|
|
@ -43,7 +43,6 @@ export const createEndpointListItemRoute = (router: ListsPluginRouter): void =>
|
|||
comments,
|
||||
description,
|
||||
entries,
|
||||
expire_time: expireTime,
|
||||
item_id: itemId,
|
||||
os_types: osTypes,
|
||||
type,
|
||||
|
@ -63,7 +62,6 @@ export const createEndpointListItemRoute = (router: ListsPluginRouter): void =>
|
|||
comments,
|
||||
description,
|
||||
entries,
|
||||
expireTime,
|
||||
itemId,
|
||||
meta,
|
||||
name,
|
||||
|
|
|
@ -49,7 +49,6 @@ export const updateEndpointListItemRoute = (router: ListsPluginRouter): void =>
|
|||
entries,
|
||||
item_id: itemId,
|
||||
tags,
|
||||
expire_time: expireTime,
|
||||
} = request.body;
|
||||
const exceptionLists = await getExceptionListClient(context);
|
||||
const exceptionListItem = await exceptionLists.updateEndpointListItem({
|
||||
|
@ -57,7 +56,6 @@ export const updateEndpointListItemRoute = (router: ListsPluginRouter): void =>
|
|||
comments,
|
||||
description,
|
||||
entries,
|
||||
expireTime,
|
||||
id,
|
||||
itemId,
|
||||
meta,
|
||||
|
|
|
@ -65,7 +65,7 @@ export const updateExceptionListItemRoute = (router: ListsPluginRouter): void =>
|
|||
});
|
||||
} else {
|
||||
const exceptionLists = await getExceptionListClient(context);
|
||||
const exceptionListItem = await exceptionLists.updateExceptionListItem({
|
||||
const exceptionListItem = await exceptionLists.updateOverwriteExceptionListItem({
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
|
|
|
@ -83,6 +83,7 @@ export const duplicateExceptionListAndItems = async ({
|
|||
comments: [],
|
||||
description: item.description,
|
||||
entries: item.entries,
|
||||
expire_time: item.expire_time,
|
||||
item_id: newItemId,
|
||||
list_id: newlyCreatedList.list_id,
|
||||
meta: item.meta,
|
||||
|
|
|
@ -97,6 +97,7 @@ import { findExceptionListsItemPointInTimeFinder } from './find_exception_list_i
|
|||
import { findValueListExceptionListItemsPointInTimeFinder } from './find_value_list_exception_list_items_point_in_time_finder';
|
||||
import { findExceptionListItemPointInTimeFinder } from './find_exception_list_item_point_in_time_finder';
|
||||
import { duplicateExceptionListAndItems } from './duplicate_exception_list';
|
||||
import { updateOverwriteExceptionListItem } from './update_overwrite_exception_list_item';
|
||||
|
||||
/**
|
||||
* Class for use for exceptions that are with trusted applications or
|
||||
|
@ -287,7 +288,6 @@ export class ExceptionListClient {
|
|||
comments,
|
||||
description,
|
||||
entries,
|
||||
expireTime,
|
||||
itemId,
|
||||
meta,
|
||||
name,
|
||||
|
@ -301,7 +301,7 @@ export class ExceptionListClient {
|
|||
comments,
|
||||
description,
|
||||
entries,
|
||||
expireTime,
|
||||
expireTime: undefined, // Not currently used with endpoint exceptions
|
||||
itemId,
|
||||
listId: ENDPOINT_LIST_ID,
|
||||
meta,
|
||||
|
@ -358,7 +358,6 @@ export class ExceptionListClient {
|
|||
comments,
|
||||
description,
|
||||
entries,
|
||||
expireTime,
|
||||
id,
|
||||
itemId,
|
||||
meta,
|
||||
|
@ -374,7 +373,7 @@ export class ExceptionListClient {
|
|||
comments,
|
||||
description,
|
||||
entries,
|
||||
expireTime,
|
||||
expireTime: undefined, // Not currently used with endpoint exceptions
|
||||
id,
|
||||
itemId,
|
||||
meta,
|
||||
|
@ -579,6 +578,11 @@ export class ExceptionListClient {
|
|||
|
||||
/**
|
||||
* Update an existing exception list item
|
||||
*
|
||||
* NOTE: This method will PATCH the targeted exception list item, not fully overwrite it.
|
||||
* Any undefined fields passed in will not be changed in the existing record. To unset any
|
||||
* fields use the `updateOverwriteExceptionListItem` method
|
||||
*
|
||||
* @param options
|
||||
* @param options._version document version
|
||||
* @param options.comments user comments attached to item
|
||||
|
@ -647,6 +651,81 @@ export class ExceptionListClient {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update an existing exception list item using the overwrite method in order to behave
|
||||
* more like a PUT request rather than a PATCH request.
|
||||
*
|
||||
* This was done in order to correctly unset types via update which cannot be accomplished
|
||||
* using the regular `updateExceptionItem` method. All other results of the methods are identical
|
||||
*
|
||||
* @param options
|
||||
* @param options._version document version
|
||||
* @param options.comments user comments attached to item
|
||||
* @param options.entries item exception entries logic
|
||||
* @param options.id the "id" of the exception list item
|
||||
* @param options.description a description of the exception list
|
||||
* @param options.itemId the "item_id" of the exception list item
|
||||
* @param options.meta Optional meta data about the exception list item
|
||||
* @param options.name the "name" of the exception list
|
||||
* @param options.namespaceType saved object namespace (single | agnostic)
|
||||
* @param options.osTypes item os types to apply
|
||||
* @param options.tags user assigned tags of exception list
|
||||
* @param options.type container type
|
||||
* @returns the updated exception list item or null if none exists
|
||||
*/
|
||||
public updateOverwriteExceptionListItem = async ({
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
expireTime,
|
||||
id,
|
||||
itemId,
|
||||
meta,
|
||||
name,
|
||||
namespaceType,
|
||||
osTypes,
|
||||
tags,
|
||||
type,
|
||||
}: UpdateExceptionListItemOptions): Promise<ExceptionListItemSchema | null> => {
|
||||
const { savedObjectsClient, user } = this;
|
||||
let updatedItem: UpdateExceptionListItemOptions = {
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
expireTime,
|
||||
id,
|
||||
itemId,
|
||||
meta,
|
||||
name,
|
||||
namespaceType,
|
||||
osTypes,
|
||||
tags,
|
||||
type,
|
||||
};
|
||||
|
||||
if (this.enableServerExtensionPoints) {
|
||||
updatedItem = await this.serverExtensionsClient.pipeRun(
|
||||
'exceptionsListPreUpdateItem',
|
||||
updatedItem,
|
||||
this.getServerExtensionCallbackContext(),
|
||||
(data) => {
|
||||
return validateData(
|
||||
updateExceptionListItemSchema,
|
||||
transformUpdateExceptionListItemOptionsToUpdateExceptionListItemSchema(data)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return updateOverwriteExceptionListItem({
|
||||
...updatedItem,
|
||||
savedObjectsClient,
|
||||
user,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete an exception list item by either id or item_id
|
||||
* @param options
|
||||
|
|
|
@ -274,8 +274,6 @@ export interface CreateEndpointListItemOptions {
|
|||
comments: CreateCommentsArray;
|
||||
/** The entries of the endpoint list item */
|
||||
entries: EntriesArray;
|
||||
/** an optional datetime string with an expiration time */
|
||||
expireTime: ExpireTimeOrUndefined;
|
||||
/** The item id of the list item */
|
||||
itemId: ItemId;
|
||||
/** The name of the list item */
|
||||
|
@ -347,8 +345,6 @@ export interface UpdateEndpointListItemOptions {
|
|||
comments: UpdateCommentsArray;
|
||||
/** The entries of the endpoint list item */
|
||||
entries: EntriesArray;
|
||||
/** an optional datetime string with an expiration time */
|
||||
expireTime: ExpireTimeOrUndefined;
|
||||
/** The id of the list item (Either this or itemId has to be defined) */
|
||||
id: IdOrUndefined;
|
||||
/** The item id of the list item (Either this or id has to be defined) */
|
||||
|
|
|
@ -32,7 +32,7 @@ import {
|
|||
} from './utils';
|
||||
import { getExceptionListItem } from './get_exception_list_item';
|
||||
|
||||
interface UpdateExceptionListItemOptions {
|
||||
export interface UpdateExceptionListItemOptions {
|
||||
id: IdOrUndefined;
|
||||
comments: UpdateCommentsArrayOrUndefined;
|
||||
_version: _VersionOrUndefined;
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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 { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types';
|
||||
import { getSavedObjectType } from '@kbn/securitysolution-list-utils';
|
||||
|
||||
import { ExceptionListSoSchema } from '../../schemas/saved_objects';
|
||||
|
||||
import {
|
||||
transformSavedObjectUpdateToExceptionListItem,
|
||||
transformUpdateCommentsToComments,
|
||||
} from './utils';
|
||||
import { getExceptionListItem } from './get_exception_list_item';
|
||||
import { UpdateExceptionListItemOptions } from './update_exception_list_item';
|
||||
|
||||
export const updateOverwriteExceptionListItem = async ({
|
||||
_version,
|
||||
comments,
|
||||
entries,
|
||||
expireTime,
|
||||
id,
|
||||
savedObjectsClient,
|
||||
namespaceType,
|
||||
name,
|
||||
osTypes,
|
||||
description,
|
||||
itemId,
|
||||
meta,
|
||||
user,
|
||||
tags,
|
||||
type,
|
||||
}: UpdateExceptionListItemOptions): Promise<ExceptionListItemSchema | null> => {
|
||||
const savedObjectType = getSavedObjectType({ namespaceType });
|
||||
const exceptionListItem = await getExceptionListItem({
|
||||
id,
|
||||
itemId,
|
||||
namespaceType,
|
||||
savedObjectsClient,
|
||||
});
|
||||
if (exceptionListItem == null) {
|
||||
return null;
|
||||
} else {
|
||||
const transformedComments = transformUpdateCommentsToComments({
|
||||
comments,
|
||||
existingComments: exceptionListItem.comments,
|
||||
user,
|
||||
});
|
||||
const savedObject = await savedObjectsClient.create<ExceptionListSoSchema>(
|
||||
savedObjectType,
|
||||
{
|
||||
comments: transformedComments,
|
||||
created_at: exceptionListItem.created_at,
|
||||
created_by: exceptionListItem.created_by,
|
||||
description: description ?? exceptionListItem.description,
|
||||
entries,
|
||||
expire_time: expireTime,
|
||||
immutable: undefined,
|
||||
item_id: itemId,
|
||||
list_id: exceptionListItem.list_id,
|
||||
list_type: 'item',
|
||||
meta,
|
||||
name: name ?? exceptionListItem.name,
|
||||
os_types: osTypes,
|
||||
tags: tags ?? exceptionListItem.tags,
|
||||
tie_breaker_id: exceptionListItem.tie_breaker_id,
|
||||
type: type ?? exceptionListItem.type,
|
||||
updated_by: user,
|
||||
version: exceptionListItem._version ? parseInt(exceptionListItem._version, 10) : undefined,
|
||||
},
|
||||
{
|
||||
id,
|
||||
overwrite: true,
|
||||
version: _version,
|
||||
}
|
||||
);
|
||||
return transformSavedObjectUpdateToExceptionListItem({
|
||||
exceptionListItem,
|
||||
savedObject,
|
||||
});
|
||||
}
|
||||
};
|
|
@ -228,7 +228,7 @@ export const transformSavedObjectUpdateToExceptionListItem = ({
|
|||
created_by: exceptionListItem.created_by,
|
||||
description: description ?? exceptionListItem.description,
|
||||
entries: entries ?? exceptionListItem.entries,
|
||||
expire_time: expireTime ?? exceptionListItem.expire_time,
|
||||
expire_time: expireTime,
|
||||
id,
|
||||
item_id: exceptionListItem.item_id,
|
||||
list_id: exceptionListItem.list_id,
|
||||
|
|
|
@ -535,12 +535,16 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({
|
|||
newCommentValue={newComment}
|
||||
newCommentOnChange={setComment}
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<ExceptionsExpireTime
|
||||
expireTime={expireTime}
|
||||
setExpireTime={setExpireTime}
|
||||
setExpireError={setExpireError}
|
||||
/>
|
||||
{listType !== ExceptionListTypeEnum.ENDPOINT && (
|
||||
<>
|
||||
<EuiHorizontalRule />
|
||||
<ExceptionsExpireTime
|
||||
expireTime={expireTime}
|
||||
setExpireTime={setExpireTime}
|
||||
setExpireError={setExpireError}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{showAlertCloseOptions && (
|
||||
<>
|
||||
<EuiHorizontalRule />
|
||||
|
|
|
@ -229,7 +229,7 @@ const ExceptionsViewerComponent = ({
|
|||
);
|
||||
|
||||
const exceptionListFilter = useMemo(() => {
|
||||
if (exceptionsToShow.active && exceptionsToShow.expired) {
|
||||
if (isEndpointSpecified || (exceptionsToShow.active && exceptionsToShow.expired)) {
|
||||
return undefined;
|
||||
}
|
||||
const savedObjectPrefixes = getSavedObjectTypes({
|
||||
|
@ -241,7 +241,7 @@ const ExceptionsViewerComponent = ({
|
|||
if (exceptionsToShow.expired) {
|
||||
return buildShowExpiredExceptionsFilter(savedObjectPrefixes);
|
||||
}
|
||||
}, [exceptionsToShow, namespaceTypes]);
|
||||
}, [exceptionsToShow, namespaceTypes, isEndpointSpecified]);
|
||||
|
||||
const handleFetchItems = useCallback(
|
||||
async (options?: GetExceptionItemProps) => {
|
||||
|
@ -516,6 +516,7 @@ const ExceptionsViewerComponent = ({
|
|||
exceptionsToShow={exceptionsToShow}
|
||||
onChangeExceptionsToShow={handleExceptionsToShow}
|
||||
lastUpdated={lastUpdated}
|
||||
isEndpoint={isEndpointSpecified}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
<ExceptionsViewerSearchBar
|
||||
|
|
|
@ -25,6 +25,7 @@ describe('ExceptionsViewerUtility', () => {
|
|||
exceptionsToShow={{ active: true }}
|
||||
onChangeExceptionsToShow={(optionId: string) => {}}
|
||||
lastUpdated={1660534202}
|
||||
isEndpoint={false}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
@ -47,6 +48,7 @@ describe('ExceptionsViewerUtility', () => {
|
|||
exceptionsToShow={{ active: true }}
|
||||
onChangeExceptionsToShow={(optionId: string) => {}}
|
||||
lastUpdated={Date.now()}
|
||||
isEndpoint={false}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
|
|
@ -42,6 +42,7 @@ interface ExceptionsViewerUtilityProps {
|
|||
lastUpdated: string | number;
|
||||
exceptionsToShow: { [id: string]: boolean };
|
||||
onChangeExceptionsToShow: (optionId: string) => void;
|
||||
isEndpoint: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,6 +53,7 @@ const ExceptionsViewerUtilityComponent: React.FC<ExceptionsViewerUtilityProps> =
|
|||
lastUpdated,
|
||||
exceptionsToShow,
|
||||
onChangeExceptionsToShow,
|
||||
isEndpoint,
|
||||
}): JSX.Element => {
|
||||
return (
|
||||
<MyUtilities>
|
||||
|
@ -88,22 +90,24 @@ const ExceptionsViewerUtilityComponent: React.FC<ExceptionsViewerUtilityProps> =
|
|||
/>
|
||||
</EuiText>
|
||||
</UtilityBarText>
|
||||
<EuiButtonGroup
|
||||
legend="Displayed exceptions button group"
|
||||
options={[
|
||||
{
|
||||
id: `active`,
|
||||
label: i18n.ACTIVE_EXCEPTIONS,
|
||||
},
|
||||
{
|
||||
id: `expired`,
|
||||
label: i18n.EXPIRED_EXCEPTIONS,
|
||||
},
|
||||
]}
|
||||
idToSelectedMap={exceptionsToShow}
|
||||
onChange={onChangeExceptionsToShow}
|
||||
type="multi"
|
||||
/>
|
||||
{!isEndpoint && (
|
||||
<EuiButtonGroup
|
||||
legend="Displayed exceptions button group"
|
||||
options={[
|
||||
{
|
||||
id: `active`,
|
||||
label: i18n.ACTIVE_EXCEPTIONS,
|
||||
},
|
||||
{
|
||||
id: `expired`,
|
||||
label: i18n.EXPIRED_EXCEPTIONS,
|
||||
},
|
||||
]}
|
||||
idToSelectedMap={exceptionsToShow}
|
||||
onChange={onChangeExceptionsToShow}
|
||||
type="multi"
|
||||
/>
|
||||
)}
|
||||
</StyledBarGroup>
|
||||
</UtilityBarSection>
|
||||
</UtilityBar>
|
||||
|
|
|
@ -400,12 +400,16 @@ const EditExceptionFlyoutComponent: React.FC<EditExceptionFlyoutProps> = ({
|
|||
newCommentValue={newComment}
|
||||
newCommentOnChange={setComment}
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<ExceptionsExpireTime
|
||||
expireTime={expireTime}
|
||||
setExpireTime={setExpireTime}
|
||||
setExpireError={setExpireError}
|
||||
/>
|
||||
{listType !== ExceptionListTypeEnum.ENDPOINT && (
|
||||
<>
|
||||
<EuiHorizontalRule />
|
||||
<ExceptionsExpireTime
|
||||
expireTime={expireTime}
|
||||
setExpireTime={setExpireTime}
|
||||
setExpireError={setExpireError}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{showAlertCloseOptions && (
|
||||
<>
|
||||
<EuiHorizontalRule />
|
||||
|
|
|
@ -66,11 +66,8 @@ export const enrichItemWithName =
|
|||
*/
|
||||
export const enrichItemWithExpireTime =
|
||||
(expireTimeToAdd: Moment | undefined) =>
|
||||
(items: ExceptionsBuilderReturnExceptionItem[]): ExceptionsBuilderReturnExceptionItem[] => {
|
||||
return expireTimeToAdd != null
|
||||
? enrichNewExceptionItemsWithExpireTime(items, expireTimeToAdd)
|
||||
: items;
|
||||
};
|
||||
(items: ExceptionsBuilderReturnExceptionItem[]): ExceptionsBuilderReturnExceptionItem[] =>
|
||||
enrichNewExceptionItemsWithExpireTime(items, expireTimeToAdd);
|
||||
|
||||
/**
|
||||
* Modifies item entries to be in correct format and adds os selection to items
|
||||
|
|
|
@ -186,12 +186,13 @@ export const enrichNewExceptionItemsWithComments = (
|
|||
*/
|
||||
export const enrichNewExceptionItemsWithExpireTime = (
|
||||
exceptionItems: ExceptionsBuilderReturnExceptionItem[],
|
||||
expireTime: Moment
|
||||
expireTime: Moment | undefined
|
||||
): ExceptionsBuilderReturnExceptionItem[] => {
|
||||
const expireTimeDateString = expireTime !== undefined ? expireTime.toISOString() : undefined;
|
||||
return exceptionItems.map((item: ExceptionsBuilderReturnExceptionItem) => {
|
||||
return {
|
||||
...item,
|
||||
expire_time: expireTime.toISOString(),
|
||||
expire_time: expireTimeDateString,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
|
|
@ -124,7 +124,6 @@ const MetaRule = t.intersection([
|
|||
}),
|
||||
]);
|
||||
|
||||
// TODO: make a ticket
|
||||
export const RuleSchema = t.intersection([
|
||||
t.type({
|
||||
author: RuleAuthorArray,
|
||||
|
|
|
@ -125,7 +125,18 @@ export const useExceptionsListCard = ({
|
|||
key: 'Export',
|
||||
icon: 'exportAction',
|
||||
label: i18n.EXPORT_EXCEPTION_LIST,
|
||||
onClick: (e: React.MouseEvent<Element, MouseEvent>) => setShowExportModal(true),
|
||||
onClick: (e: React.MouseEvent<Element, MouseEvent>) => {
|
||||
if (listType === ExceptionListTypeEnum.ENDPOINT) {
|
||||
handleExport({
|
||||
id: exceptionsList.id,
|
||||
listId: exceptionsList.list_id,
|
||||
namespaceType: exceptionsList.namespace_type,
|
||||
includeExpiredExceptions: true,
|
||||
})();
|
||||
} else {
|
||||
setShowExportModal(true);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'Delete',
|
||||
|
@ -158,6 +169,8 @@ export const useExceptionsListCard = ({
|
|||
setShowExportModal,
|
||||
listCannotBeEdited,
|
||||
handleManageRules,
|
||||
handleExport,
|
||||
listType,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
} from '@kbn/securitysolution-exception-list-components';
|
||||
import { EuiLoadingContent } from '@elastic/eui';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types';
|
||||
import { SecurityPageName } from '../../../../common/constants';
|
||||
import { SpyRoute } from '../../../common/utils/route/spy_routes';
|
||||
import { ReferenceErrorModal } from '../../../detections/components/value_lists_management_flyout/reference_error_modal';
|
||||
|
@ -67,6 +68,14 @@ export const ListsDetailViewComponent: FC = () => {
|
|||
|
||||
const onModalOpen = useCallback(() => setShowExportModal(true), [setShowExportModal]);
|
||||
|
||||
const handleExportList = useCallback(() => {
|
||||
if (list?.type === ExceptionListTypeEnum.ENDPOINT) {
|
||||
onExportList(true);
|
||||
} else {
|
||||
onModalOpen();
|
||||
}
|
||||
}, [onModalOpen, list, onExportList]);
|
||||
|
||||
const detailsViewContent = useMemo(() => {
|
||||
if (viewerStatus === ViewerStatus.ERROR)
|
||||
return <EmptyViewerState isReadOnly={isReadOnly} viewerStatus={viewerStatus} />;
|
||||
|
@ -87,7 +96,7 @@ export const ListsDetailViewComponent: FC = () => {
|
|||
backOptions={headerBackOptions}
|
||||
securityLinkAnchorComponent={ListDetailsLinkAnchor}
|
||||
onEditListDetails={onEditListDetails}
|
||||
onExportList={onModalOpen}
|
||||
onExportList={handleExportList}
|
||||
onDeleteList={handleDelete}
|
||||
onManageRules={onManageRules}
|
||||
/>
|
||||
|
@ -155,7 +164,7 @@ export const ListsDetailViewComponent: FC = () => {
|
|||
handleDelete,
|
||||
handleReferenceDelete,
|
||||
onModalClose,
|
||||
onModalOpen,
|
||||
handleExportList,
|
||||
]);
|
||||
return (
|
||||
<>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue