Skip to content
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

[SIEM][Exceptions] - ExceptionsViewer UI component part 2 #68294

Merged
merged 35 commits into from
Jun 10, 2020
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
24ed91f
moved and_or_badge to common folder and added tests
yctercero Jun 2, 2020
629b832
updated references to new and_or_badge location
yctercero Jun 2, 2020
335a720
built out exception item component for viewer
yctercero Jun 2, 2020
dd2b8c8
added exception item component stories for easy testing
yctercero Jun 2, 2020
990d656
updated text to use i18n in spots missed
yctercero Jun 2, 2020
bac11c9
added tests for exception detail component and updated braking tests
yctercero Jun 2, 2020
9496085
finished adding tests and fixing lint issue
yctercero Jun 3, 2020
f3a1fba
fixed test timestamps to be UTC
yctercero Jun 3, 2020
a8a68fa
fix failing test that was passing locally
yctercero Jun 3, 2020
f0aeda8
tests
yctercero Jun 3, 2020
b19237f
fix dates
yctercero Jun 3, 2020
3a31452
fixes per feedback
yctercero Jun 3, 2020
7ad2a23
Merge branch 'master' of github.com:yctercero/kibana into all-exc-view
yctercero Jun 3, 2020
053c5d7
cleanup
yctercero Jun 3, 2020
c24c1ff
updated tests
yctercero Jun 3, 2020
8b91e10
Merge branch 'master' of github.com:yctercero/kibana into all-exc-view
yctercero Jun 4, 2020
878547e
updated translations to use securitySolution after rename
yctercero Jun 4, 2020
410ecb9
Merge branch 'all-exc-view' of https://github.com/yctercero/kibana in…
yctercero Jun 4, 2020
bc7b81e
updated useExceptionList hook to use different refresh pattern, updat…
yctercero Jun 4, 2020
798b1dd
moved exception item component into its own folder
yctercero Jun 4, 2020
29810e7
added search bar, toggle, and buttons
yctercero Jun 4, 2020
da467bf
added exceptions viewer component
yctercero Jun 4, 2020
c953d0f
Merge branch 'master' of github.com:yctercero/kibana into exceptions-…
yctercero Jun 4, 2020
32f66d2
fix merge issue
yctercero Jun 4, 2020
8de7469
some cleanup
yctercero Jun 4, 2020
c333567
modified list scripts for help with testing
yctercero Jun 5, 2020
8a51155
added exceptions hook for general api usage, updated exception item
yctercero Jun 8, 2020
9196387
updated per feedback to allow for different filtering
yctercero Jun 8, 2020
3117815
Merge branch 'master' of github.com:yctercero/kibana into exceptions-…
yctercero Jun 8, 2020
aea3b16
temp disabled complexity linter for rules/details/index, this file is…
yctercero Jun 8, 2020
854892a
cleanup
yctercero Jun 8, 2020
5303cc9
updated hook tests and clean up
yctercero Jun 8, 2020
6027cbb
updated and added more tests, cleaned up linter issues and per page s…
yctercero Jun 9, 2020
2f8eb18
update typing
yctercero Jun 9, 2020
77fd167
Merge branch 'master' into exceptions-viewer-2
elasticmachine Jun 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import * as api from '../api';
import { createKibanaCoreStartMock } from '../../common/mocks/kibana_core';
import { getExceptionListSchemaMock } from '../../../common/schemas/response/exception_list_schema.mock';
import { getExceptionListItemSchemaMock } from '../../../common/schemas/response/exception_list_item_schema.mock';
import { ExceptionListAndItems, UseExceptionListProps } from '../types';
import { ExceptionListSchema } from '../../../common/schemas';
import { ExceptionItemsAndPagination, UseExceptionListProps } from '../types';

import { ReturnExceptionListAndItems, useExceptionList } from './use_exception_list';

Expand Down Expand Up @@ -41,8 +42,7 @@ describe('useExceptionList', () => {
);
await waitForNextUpdate();

expect(result.current).toEqual([true, null, result.current[2]]);
expect(typeof result.current[2]).toEqual('function');
expect(result.current).toEqual([true, null, null, null]);
});
});

Expand All @@ -62,19 +62,23 @@ describe('useExceptionList', () => {
await waitForNextUpdate();
await waitForNextUpdate();

const expectedResult: ExceptionListAndItems = {
...getExceptionListSchemaMock(),
exceptionItems: {
items: [{ ...getExceptionListItemSchemaMock() }],
pagination: {
page: 1,
perPage: 20,
total: 1,
},
const expectedListResult: ExceptionListSchema = getExceptionListSchemaMock();

const expectedListItemsResult: ExceptionItemsAndPagination = {
items: [getExceptionListItemSchemaMock()],
pagination: {
page: 1,
perPage: 20,
total: 1,
},
};

expect(result.current).toEqual([false, expectedResult, result.current[2]]);
expect(result.current).toEqual([
false,
expectedListResult,
expectedListItemsResult,
result.current[3],
]);
});
});

Expand Down Expand Up @@ -128,7 +132,13 @@ describe('useExceptionList', () => {
);
await waitForNextUpdate();
await waitForNextUpdate();
result.current[2]();

expect(typeof result.current[3]).toEqual('function');

if (result.current[3] != null) {
result.current[3]({ listId: 'myListId', listNamespaceType: 'single' });
}

await waitForNextUpdate();

expect(spyOnfetchExceptionListById).toHaveBeenCalledTimes(2);
Expand Down
124 changes: 62 additions & 62 deletions x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { useCallback, useEffect, useState } from 'react';
import { useEffect, useMemo, useRef, useState } from 'react';

import { fetchExceptionListById, fetchExceptionListItemsByListId } from '../api';
import { ExceptionListAndItems, UseExceptionListProps } from '../types';
import {
ExceptionItemsAndPagination,
UseExceptionListProps,
UseExceptionListRefreshProps,
} from '../types';
import { ExceptionListSchema } from '../../../common/schemas';

export type ReturnExceptionListAndItems = [boolean, ExceptionListAndItems | null, () => void];
type Func = (arg: UseExceptionListRefreshProps) => void;
export type ReturnExceptionListAndItems = [
boolean,
ExceptionListSchema | null,
ExceptionItemsAndPagination | null,
Func | null
];

/**
* Hook for using to get an ExceptionList and it's ExceptionListItems
Expand Down Expand Up @@ -37,64 +48,60 @@ export const useExceptionList = ({
},
onError,
}: UseExceptionListProps): ReturnExceptionListAndItems => {
const [exceptionListAndItems, setExceptionList] = useState<ExceptionListAndItems | null>(null);
const [shouldRefresh, setRefresh] = useState<boolean>(true);
const refreshExceptionList = useCallback(() => setRefresh(true), [setRefresh]);
const [exceptionList, setExceptionList] = useState<ExceptionListSchema | null>(null);
const [exceptionItems, setExceptionListItems] = useState<ExceptionItemsAndPagination | null>(
null
);
const fetchExceptionList = useRef<Func | null>(null);
yctercero marked this conversation as resolved.
Show resolved Hide resolved
const [loading, setLoading] = useState(true);
const tags = filterOptions.tags.sort().join();
const tags = useMemo(() => filterOptions.tags.sort().join(), [filterOptions.tags]);

useEffect(
() => {
let isSubscribed = true;
const abortCtrl = new AbortController();

const fetchData = async (idToFetch: string): Promise<void> => {
if (shouldRefresh) {
try {
setLoading(true);
const fetchData = async ({
listId,
listNamespaceType,
}: UseExceptionListRefreshProps): Promise<void> => {
try {
setLoading(true);

const { list_id, namespace_type, ...restOfExceptionList } = await fetchExceptionListById({
http,
id: listId,
namespaceType: listNamespaceType,
signal: abortCtrl.signal,
});
const fetchListItemsResult = await fetchExceptionListItemsByListId({
filterOptions,
http,
listId: list_id,
namespaceType: namespace_type,
pagination,
signal: abortCtrl.signal,
});

const {
if (isSubscribed) {
setExceptionList({
list_id,
namespace_type,
...restOfExceptionList
} = await fetchExceptionListById({
http,
id: idToFetch,
namespaceType,
signal: abortCtrl.signal,
...restOfExceptionList,
});
const fetchListItemsResult = await fetchExceptionListItemsByListId({
filterOptions,
http,
listId: list_id,
namespaceType: namespace_type,
pagination,
signal: abortCtrl.signal,
setExceptionListItems({
items: [...fetchListItemsResult.data],
pagination: {
page: fetchListItemsResult.page,
perPage: fetchListItemsResult.per_page,
total: fetchListItemsResult.total,
},
});

setRefresh(false);

if (isSubscribed) {
setExceptionList({
list_id,
namespace_type,
...restOfExceptionList,
exceptionItems: {
items: [...fetchListItemsResult.data],
pagination: {
page: fetchListItemsResult.page,
perPage: fetchListItemsResult.per_page,
total: fetchListItemsResult.total,
},
},
});
}
} catch (error) {
setRefresh(false);
if (isSubscribed) {
setExceptionList(null);
onError(error);
}
}
} catch (error) {
if (isSubscribed) {
setExceptionList(null);
onError(error);
}
}

Expand All @@ -103,25 +110,18 @@ export const useExceptionList = ({
}
};

if (id != null) {
fetchData(id);
if (id != null && namespaceType != null) {
fetchData({ listId: id, listNamespaceType: namespaceType });
}

fetchExceptionList.current = fetchData;
return (): void => {
isSubscribed = false;
abortCtrl.abort();
};
}, // eslint-disable-next-line react-hooks/exhaustive-deps
[
http,
id,
onError,
shouldRefresh,
pagination.page,
pagination.perPage,
filterOptions.filter,
tags,
]
[http, id, namespaceType, pagination.page, pagination.perPage, filterOptions.filter, tags]
);

return [loading, exceptionListAndItems, refreshExceptionList];
return [loading, exceptionList, exceptionItems, fetchExceptionList.current];
};
9 changes: 5 additions & 4 deletions x-pack/plugins/lists/public/exceptions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ export interface ExceptionItemsAndPagination {
pagination: Pagination;
}

export interface ExceptionListAndItems extends ExceptionListSchema {
exceptionItems: ExceptionItemsAndPagination;
}

export type AddExceptionList = ExceptionListSchema | CreateExceptionListSchemaPartial;

export type AddExceptionListItem = CreateExceptionListItemSchemaPartial | ExceptionListItemSchema;
Expand All @@ -51,6 +47,11 @@ export interface UseExceptionListProps {
pagination?: Pagination;
}

export interface UseExceptionListRefreshProps {
listId: string;
listNamespaceType: NamespaceType;
}

export interface ApiCallByListIdProps {
http: HttpStart;
listId: string;
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/lists/public/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
export { usePersistExceptionItem } from './exceptions/hooks/persist_exception_item';
export { usePersistExceptionList } from './exceptions/hooks/persist_exception_list';
export { useExceptionList } from './exceptions/hooks/use_exception_list';
export { deleteExceptionListItemById } from './exceptions/api';
export { mockNewExceptionItem, mockNewExceptionList } from './exceptions/mock';
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"list_id": "detection_list",
"_tags": ["detection"],
"tags": ["detection", "sample_tag"],
"type": "detection",
"description": "This is a sample detection type exception list",
"name": "Sample Detection Exception List",
"namespace_type": "single"
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"type": "simple",
"description": "This is a sample endpoint type exception that has no item_id so it creates a new id each time",
"name": "Sample Endpoint Exception List",
"comment": [],
"entries": [
{
"field": "actingProcess.file.signer",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"list_id": "detection_list",
"_tags": ["detection"],
"tags": ["test_tag", "detection", "no_more_bad_guys"],
"type": "simple",
"description": "This is a sample detection type exception that has no item_id so it creates a new id each time",
"name": "Sample Detection Exception List Item",
"comment": [],
"entries": [
{
"field": "host.name",
"operator": "included",
"match": "sampleHostName"
},
{
"field": "event.category",
"operator": "included",
"match_any": ["process", "malware"]
},
{
"field": "event.action",
"operator": "included",
"match": "user-password-change"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,12 @@ import { FailureHistory } from './failure_history';
import { RuleStatus } from '../../../../components/rules//rule_status';
import { useMlCapabilities } from '../../../../../common/components/ml_popover/hooks/use_ml_capabilities';
import { hasMlAdminPermissions } from '../../../../../../common/machine_learning/has_ml_admin_permissions';
import { ExceptionsViewer } from '../../../../../common/components/exceptions/viewer';

enum RuleDetailTabs {
alerts = 'alerts',
failures = 'failures',
exceptions = 'exceptions',
}

const ruleDetailTabs = [
Expand All @@ -82,6 +84,11 @@ const ruleDetailTabs = [
name: detectionI18n.ALERT,
disabled: false,
},
{
id: RuleDetailTabs.exceptions,
name: i18n.EXCEPTIONS_TAB,
disabled: false,
},
{
id: RuleDetailTabs.failures,
name: i18n.FAILURE_HISTORY_TAB,
Expand Down Expand Up @@ -385,6 +392,12 @@ export const RuleDetailsPageComponent: FC<PropsFromRedux> = ({
)}
</>
)}
{ruleDetailTab === RuleDetailTabs.exceptions && (
<ExceptionsViewer
commentsAccordionId={'ruleDetailsTabExceptions'}
exceptionLists={[]}
/>
)}
yctercero marked this conversation as resolved.
Show resolved Hide resolved
{ruleDetailTab === RuleDetailTabs.failures && <FailureHistory id={rule?.id} />}
</WrapperPage>
</StickyContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,10 @@ export const TYPE_FAILED = i18n.translate(
defaultMessage: 'Failed',
}
);

export const EXCEPTIONS_TAB = i18n.translate(
'xpack.securitySolution.detectionEngine.ruleDetails.exceptionsTab',
{
defaultMessage: 'Exceptions',
}
);
Loading