mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security Solution][Exceptions] - Update exceptions tab privileges checks (#122902)
### Summary Addresses #122227.
This commit is contained in:
parent
8c11be1154
commit
fc64d172e7
17 changed files with 196 additions and 82 deletions
|
@ -88,7 +88,7 @@ export const getReadPrivilegeMock = (
|
|||
manage_index_templates: booleanValues,
|
||||
manage_ingest_pipelines: booleanValues,
|
||||
manage_ml: booleanValues,
|
||||
manage_own_api_key: false,
|
||||
manage_own_api_key: booleanValues,
|
||||
manage_pipeline: booleanValues,
|
||||
manage_rollup: booleanValues,
|
||||
manage_saml: booleanValues,
|
||||
|
@ -105,7 +105,7 @@ export const getReadPrivilegeMock = (
|
|||
read_ilm: booleanValues,
|
||||
transport_client: booleanValues,
|
||||
},
|
||||
has_all_requested: false,
|
||||
has_all_requested: booleanValues,
|
||||
index: {
|
||||
[listItemsIndex]: {
|
||||
all: booleanValues,
|
||||
|
@ -141,7 +141,7 @@ export const getReadPrivilegeMock = (
|
|||
manage_index_templates: booleanValues,
|
||||
manage_ingest_pipelines: booleanValues,
|
||||
manage_ml: booleanValues,
|
||||
manage_own_api_key: false,
|
||||
manage_own_api_key: booleanValues,
|
||||
manage_pipeline: booleanValues,
|
||||
manage_rollup: booleanValues,
|
||||
manage_saml: booleanValues,
|
||||
|
@ -158,7 +158,7 @@ export const getReadPrivilegeMock = (
|
|||
read_ilm: booleanValues,
|
||||
transport_client: booleanValues,
|
||||
},
|
||||
has_all_requested: false,
|
||||
has_all_requested: booleanValues,
|
||||
index: {
|
||||
[listIndex]: {
|
||||
all: booleanValues,
|
||||
|
|
|
@ -20,7 +20,7 @@ import { login, loginAndWaitForPage, waitForPageWithoutDateRange } from '../../t
|
|||
import { refreshPage } from '../../tasks/security_header';
|
||||
|
||||
import { ALERTS_URL } from '../../urls/navigation';
|
||||
import { ATTACH_ALERT_TO_CASE_BUTTON } from '../../screens/alerts';
|
||||
import { ATTACH_ALERT_TO_CASE_BUTTON, TIMELINE_CONTEXT_MENU_BTN } from '../../screens/alerts';
|
||||
|
||||
const loadDetectionsPage = (role: ROLES) => {
|
||||
waitForPageWithoutDateRange(ALERTS_URL, role);
|
||||
|
@ -48,8 +48,8 @@ describe('Alerts timeline', () => {
|
|||
});
|
||||
|
||||
it('should not allow user with read only privileges to attach alerts to cases', () => {
|
||||
expandFirstAlertActions();
|
||||
cy.get(ATTACH_ALERT_TO_CASE_BUTTON).should('not.exist');
|
||||
// Disabled actions for read only users are hidden, so actions button should not show
|
||||
cy.get(TIMELINE_CONTEXT_MENU_BTN).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ describe('ExceptionEntries', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionEntries
|
||||
disableDelete={false}
|
||||
disableActions={false}
|
||||
entries={[getFormattedEntryMock()]}
|
||||
onDelete={jest.fn()}
|
||||
onEdit={jest.fn()}
|
||||
|
@ -38,7 +38,7 @@ describe('ExceptionEntries', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionEntries
|
||||
disableDelete={false}
|
||||
disableActions={false}
|
||||
entries={[getFormattedEntryMock(), getFormattedEntryMock()]}
|
||||
onDelete={jest.fn()}
|
||||
onEdit={jest.fn()}
|
||||
|
@ -54,7 +54,7 @@ describe('ExceptionEntries', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionEntries
|
||||
disableDelete={false}
|
||||
disableActions={false}
|
||||
entries={[getFormattedEntryMock()]}
|
||||
onDelete={jest.fn()}
|
||||
onEdit={mockOnEdit}
|
||||
|
@ -72,7 +72,7 @@ describe('ExceptionEntries', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionEntries
|
||||
disableDelete={false}
|
||||
disableActions={false}
|
||||
entries={[getFormattedEntryMock()]}
|
||||
onDelete={mockOnDelete}
|
||||
onEdit={jest.fn()}
|
||||
|
@ -85,37 +85,36 @@ describe('ExceptionEntries', () => {
|
|||
expect(mockOnDelete).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('it renders edit button disabled if "disableDelete" is "true"', () => {
|
||||
test('it does not render edit button if "disableActions" is "true"', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionEntries
|
||||
disableDelete={true}
|
||||
disableActions={true}
|
||||
entries={[getFormattedEntryMock()]}
|
||||
onDelete={jest.fn()}
|
||||
onEdit={jest.fn()}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
const editBtn = wrapper.find('[data-test-subj="exceptionsViewerEditBtn"] button').at(0);
|
||||
const editBtns = wrapper.find('[data-test-subj="exceptionsViewerEditBtn"] button');
|
||||
|
||||
expect(editBtn.prop('disabled')).toBeTruthy();
|
||||
expect(editBtns).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('it renders delete button in loading state if "disableDelete" is "true"', () => {
|
||||
test('it does not render delete button if "disableActions" is "true"', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionEntries
|
||||
disableDelete={true}
|
||||
disableActions={true}
|
||||
entries={[getFormattedEntryMock()]}
|
||||
onDelete={jest.fn()}
|
||||
onEdit={jest.fn()}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
const deleteBtn = wrapper.find('[data-test-subj="exceptionsViewerDeleteBtn"] button').at(0);
|
||||
const deleteBtns = wrapper.find('[data-test-subj="exceptionsViewerDeleteBtn"] button').at(0);
|
||||
|
||||
expect(deleteBtn.prop('disabled')).toBeTruthy();
|
||||
expect(deleteBtn.find('.euiLoadingSpinner')).toBeTruthy();
|
||||
expect(deleteBtns).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('it renders nested entry', () => {
|
||||
|
@ -126,7 +125,7 @@ describe('ExceptionEntries', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionEntries
|
||||
disableDelete={false}
|
||||
disableActions={false}
|
||||
entries={[parentEntry, getFormattedEntryMock(true)]}
|
||||
onDelete={jest.fn()}
|
||||
onEdit={jest.fn()}
|
||||
|
@ -168,7 +167,7 @@ describe('ExceptionEntries', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionEntries
|
||||
disableDelete={false}
|
||||
disableActions={false}
|
||||
entries={[getFormattedEntryMock()]}
|
||||
onDelete={jest.fn()}
|
||||
onEdit={jest.fn()}
|
||||
|
|
|
@ -75,14 +75,14 @@ const ValueBadgeGroup = styled(EuiBadgeGroup)`
|
|||
|
||||
interface ExceptionEntriesComponentProps {
|
||||
entries: FormattedEntry[];
|
||||
disableDelete: boolean;
|
||||
disableActions: boolean;
|
||||
onDelete: () => void;
|
||||
onEdit: () => void;
|
||||
}
|
||||
|
||||
const ExceptionEntriesComponent = ({
|
||||
entries,
|
||||
disableDelete,
|
||||
disableActions,
|
||||
onDelete,
|
||||
onEdit,
|
||||
}: ExceptionEntriesComponentProps): JSX.Element => {
|
||||
|
@ -181,32 +181,32 @@ const ExceptionEntriesComponent = ({
|
|||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={1}>
|
||||
<EuiFlexGroup gutterSize="s" justifyContent="flexEnd">
|
||||
<MyActionButton grow={false}>
|
||||
<MyEditButton
|
||||
size="s"
|
||||
color="primary"
|
||||
onClick={onEdit}
|
||||
isDisabled={disableDelete}
|
||||
data-test-subj="exceptionsViewerEditBtn"
|
||||
>
|
||||
{i18n.EDIT}
|
||||
</MyEditButton>
|
||||
</MyActionButton>
|
||||
<MyActionButton grow={false}>
|
||||
<MyRemoveButton
|
||||
size="s"
|
||||
color="danger"
|
||||
onClick={onDelete}
|
||||
isLoading={disableDelete}
|
||||
data-test-subj="exceptionsViewerDeleteBtn"
|
||||
>
|
||||
{i18n.REMOVE}
|
||||
</MyRemoveButton>
|
||||
</MyActionButton>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{!disableActions && (
|
||||
<EuiFlexItem grow={1}>
|
||||
<EuiFlexGroup gutterSize="s" justifyContent="flexEnd">
|
||||
<MyActionButton grow={false}>
|
||||
<MyEditButton
|
||||
size="s"
|
||||
color="primary"
|
||||
onClick={onEdit}
|
||||
data-test-subj="exceptionsViewerEditBtn"
|
||||
>
|
||||
{i18n.EDIT}
|
||||
</MyEditButton>
|
||||
</MyActionButton>
|
||||
<MyActionButton grow={false}>
|
||||
<MyRemoveButton
|
||||
size="s"
|
||||
color="danger"
|
||||
onClick={onDelete}
|
||||
data-test-subj="exceptionsViewerDeleteBtn"
|
||||
>
|
||||
{i18n.REMOVE}
|
||||
</MyRemoveButton>
|
||||
</MyActionButton>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</MyEntriesDetails>
|
||||
);
|
||||
|
|
|
@ -35,6 +35,7 @@ storiesOf('Components/ExceptionItem', module)
|
|||
|
||||
return (
|
||||
<ExceptionItem
|
||||
disableActions={false}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
exceptionItem={payload}
|
||||
|
@ -57,6 +58,7 @@ storiesOf('Components/ExceptionItem', module)
|
|||
|
||||
return (
|
||||
<ExceptionItem
|
||||
disableActions={false}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
exceptionItem={payload}
|
||||
|
@ -80,6 +82,7 @@ storiesOf('Components/ExceptionItem', module)
|
|||
|
||||
return (
|
||||
<ExceptionItem
|
||||
disableActions={false}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
exceptionItem={payload}
|
||||
|
@ -95,6 +98,7 @@ storiesOf('Components/ExceptionItem', module)
|
|||
|
||||
return (
|
||||
<ExceptionItem
|
||||
disableActions={false}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
exceptionItem={payload}
|
||||
|
@ -108,6 +112,7 @@ storiesOf('Components/ExceptionItem', module)
|
|||
payload.comments = getCommentsArrayMock();
|
||||
return (
|
||||
<ExceptionItem
|
||||
disableActions={false}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
exceptionItem={payload}
|
||||
|
@ -122,6 +127,7 @@ storiesOf('Components/ExceptionItem', module)
|
|||
|
||||
return (
|
||||
<ExceptionItem
|
||||
disableActions={false}
|
||||
loadingItemIds={[{ id, namespaceType: namespace_type }]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
exceptionItem={{ id, namespace_type, ...rest }}
|
||||
|
@ -129,4 +135,28 @@ storiesOf('Components/ExceptionItem', module)
|
|||
onEditException={action('onClick')}
|
||||
/>
|
||||
);
|
||||
})
|
||||
.add('with actions disabled', () => {
|
||||
const payload = getExceptionListItemSchemaMock();
|
||||
payload.description = '';
|
||||
payload.comments = getCommentsArrayMock();
|
||||
payload.entries = [
|
||||
{
|
||||
field: 'actingProcess.file.signer',
|
||||
type: 'match',
|
||||
operator: 'included',
|
||||
value: 'Elastic, N.V.',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<ExceptionItem
|
||||
disableActions
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
exceptionItem={payload}
|
||||
onDeleteException={action('onClick')}
|
||||
onEditException={action('onClick')}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -32,6 +32,7 @@ describe('ExceptionItem', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionItem
|
||||
disableActions={false}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
onDeleteException={jest.fn()}
|
||||
|
@ -51,6 +52,7 @@ describe('ExceptionItem', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionItem
|
||||
disableActions={false}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
onDeleteException={jest.fn()}
|
||||
|
@ -70,6 +72,30 @@ describe('ExceptionItem', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('it does not render edit or delete action buttons when "disableActions" is "true"', () => {
|
||||
const mockOnEditException = jest.fn();
|
||||
const exceptionItem = getExceptionListItemSchemaMock();
|
||||
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionItem
|
||||
disableActions
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
onDeleteException={jest.fn()}
|
||||
onEditException={mockOnEditException}
|
||||
exceptionItem={exceptionItem}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
const editBtn = wrapper.find('[data-test-subj="exceptionsViewerEditBtn"] button');
|
||||
const deleteBtn = wrapper.find('[data-test-subj="exceptionsViewerDeleteBtn"] button');
|
||||
|
||||
expect(editBtn).toHaveLength(0);
|
||||
expect(deleteBtn).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('it invokes "onEditException" when edit button clicked', () => {
|
||||
const mockOnEditException = jest.fn();
|
||||
const exceptionItem = getExceptionListItemSchemaMock();
|
||||
|
@ -77,6 +103,7 @@ describe('ExceptionItem', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionItem
|
||||
disableActions={false}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
onDeleteException={jest.fn()}
|
||||
|
@ -99,6 +126,7 @@ describe('ExceptionItem', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionItem
|
||||
disableActions={false}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
onDeleteException={mockOnDeleteException}
|
||||
|
@ -108,8 +136,8 @@ describe('ExceptionItem', () => {
|
|||
</ThemeProvider>
|
||||
);
|
||||
|
||||
const editBtn = wrapper.find('[data-test-subj="exceptionsViewerDeleteBtn"] button').at(0);
|
||||
editBtn.simulate('click');
|
||||
const deleteBtn = wrapper.find('[data-test-subj="exceptionsViewerDeleteBtn"] button').at(0);
|
||||
deleteBtn.simulate('click');
|
||||
|
||||
expect(mockOnDeleteException).toHaveBeenCalledWith({
|
||||
id: '1',
|
||||
|
@ -124,6 +152,7 @@ describe('ExceptionItem', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionItem
|
||||
disableActions={false}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
onDeleteException={mockOnDeleteException}
|
||||
|
@ -143,6 +172,7 @@ describe('ExceptionItem', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ExceptionItem
|
||||
disableActions={false}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId={'accordion--comments'}
|
||||
onDeleteException={mockOnDeleteException}
|
||||
|
|
|
@ -38,10 +38,12 @@ export interface ExceptionItemProps {
|
|||
onEditException: (item: ExceptionListItemSchema) => void;
|
||||
showName?: boolean;
|
||||
showModified?: boolean;
|
||||
disableActions: boolean;
|
||||
'data-test-subj'?: string;
|
||||
}
|
||||
|
||||
const ExceptionItemComponent = ({
|
||||
disableActions,
|
||||
loadingItemIds,
|
||||
exceptionItem,
|
||||
commentsAccordionId,
|
||||
|
@ -78,7 +80,7 @@ const ExceptionItemComponent = ({
|
|||
return getFormattedComments(exceptionItem.comments);
|
||||
}, [exceptionItem.comments]);
|
||||
|
||||
const disableDelete = useMemo((): boolean => {
|
||||
const disableItemActions = useMemo((): boolean => {
|
||||
const foundItems = loadingItemIds.filter(({ id }) => id === exceptionItem.id);
|
||||
return foundItems.length > 0;
|
||||
}, [loadingItemIds, exceptionItem.id]);
|
||||
|
@ -96,7 +98,7 @@ const ExceptionItemComponent = ({
|
|||
showName={showName}
|
||||
/>
|
||||
<ExceptionEntries
|
||||
disableDelete={disableDelete}
|
||||
disableActions={disableItemActions || disableActions}
|
||||
entries={entryItems}
|
||||
onDelete={handleDelete}
|
||||
onEdit={handleEdit}
|
||||
|
|
|
@ -42,6 +42,22 @@ describe('ExceptionsViewerHeader', () => {
|
|||
).toBeTruthy();
|
||||
});
|
||||
|
||||
// This occurs if user does not have sufficient privileges
|
||||
it('it does not display add exception button if no list types available', () => {
|
||||
const wrapper = mount(
|
||||
<ExceptionsViewerHeader
|
||||
supportedListTypes={[]}
|
||||
isInitLoading={false}
|
||||
detectionsListItems={0}
|
||||
endpointListItems={0}
|
||||
onFilterChange={jest.fn()}
|
||||
onAddExceptionClick={jest.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="exceptionsHeaderAddExceptionBtn"]').exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('it displays toggles and add exception popover when more than one list type available', () => {
|
||||
const wrapper = mount(
|
||||
<ExceptionsViewerHeader
|
||||
|
|
|
@ -133,7 +133,7 @@ const ExceptionsViewerHeaderComponent = ({
|
|||
/>
|
||||
</EuiFlexItem>
|
||||
|
||||
{supportedListTypes.length < 2 && (
|
||||
{supportedListTypes.length === 1 && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
data-test-subj="exceptionsHeaderAddExceptionBtn"
|
||||
|
|
|
@ -29,6 +29,7 @@ describe('ExceptionsViewerItems', () => {
|
|||
showEmpty
|
||||
showNoResults={false}
|
||||
isInitLoading={false}
|
||||
disableActions={false}
|
||||
exceptions={[]}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId="comments-accordion-id"
|
||||
|
@ -54,6 +55,7 @@ describe('ExceptionsViewerItems', () => {
|
|||
showEmpty={false}
|
||||
showNoResults
|
||||
isInitLoading={false}
|
||||
disableActions={false}
|
||||
exceptions={[]}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId="comments-accordion-id"
|
||||
|
@ -78,6 +80,7 @@ describe('ExceptionsViewerItems', () => {
|
|||
showEmpty={false}
|
||||
showNoResults={false}
|
||||
isInitLoading={false}
|
||||
disableActions={false}
|
||||
exceptions={[getExceptionListItemSchemaMock()]}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId="comments-accordion-id"
|
||||
|
@ -98,6 +101,7 @@ describe('ExceptionsViewerItems', () => {
|
|||
showEmpty={false}
|
||||
showNoResults={false}
|
||||
isInitLoading={true}
|
||||
disableActions={false}
|
||||
exceptions={[]}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId="comments-accordion-id"
|
||||
|
@ -122,6 +126,7 @@ describe('ExceptionsViewerItems', () => {
|
|||
showEmpty={false}
|
||||
showNoResults={false}
|
||||
isInitLoading={false}
|
||||
disableActions={false}
|
||||
exceptions={[exception1, exception2]}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId="comments-accordion-id"
|
||||
|
@ -147,6 +152,7 @@ describe('ExceptionsViewerItems', () => {
|
|||
showEmpty={false}
|
||||
showNoResults={false}
|
||||
isInitLoading={false}
|
||||
disableActions={false}
|
||||
exceptions={[exception1, exception2]}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId="comments-accordion-id"
|
||||
|
@ -172,6 +178,7 @@ describe('ExceptionsViewerItems', () => {
|
|||
showEmpty={false}
|
||||
showNoResults={false}
|
||||
isInitLoading={false}
|
||||
disableActions={false}
|
||||
exceptions={[getExceptionListItemSchemaMock()]}
|
||||
loadingItemIds={[]}
|
||||
commentsAccordionId="comments-accordion-id"
|
||||
|
|
|
@ -36,6 +36,7 @@ interface ExceptionsViewerItemsProps {
|
|||
showEmpty: boolean;
|
||||
showNoResults: boolean;
|
||||
isInitLoading: boolean;
|
||||
disableActions: boolean;
|
||||
exceptions: ExceptionListItemSchema[];
|
||||
loadingItemIds: ExceptionListItemIdentifiers[];
|
||||
commentsAccordionId: string;
|
||||
|
@ -52,6 +53,7 @@ const ExceptionsViewerItemsComponent: React.FC<ExceptionsViewerItemsProps> = ({
|
|||
commentsAccordionId,
|
||||
onDeleteException,
|
||||
onEditExceptionItem,
|
||||
disableActions,
|
||||
}): JSX.Element => (
|
||||
<MyExceptionsContainer direction="column" className="eui-yScrollWithShadows">
|
||||
{showEmpty || showNoResults || isInitLoading ? (
|
||||
|
@ -93,6 +95,7 @@ const ExceptionsViewerItemsComponent: React.FC<ExceptionsViewerItemsProps> = ({
|
|||
<EuiSpacer size="s" />
|
||||
)}
|
||||
<ExceptionItem
|
||||
disableActions={disableActions}
|
||||
loadingItemIds={loadingItemIds}
|
||||
commentsAccordionId={commentsAccordionId}
|
||||
exceptionItem={exception}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useReducer } from 'react';
|
||||
import React, { useCallback, useEffect, useReducer, useState } from 'react';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import uuid from 'uuid';
|
||||
|
||||
|
@ -18,6 +18,7 @@ import type {
|
|||
import { useApi, useExceptionListItems } from '@kbn/securitysolution-list-hooks';
|
||||
import * as i18n from '../translations';
|
||||
import { useStateToaster } from '../../toasters';
|
||||
import { useUserData } from '../../../../../public/detections/components/user_info';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { Panel } from '../../../../common/components/panel';
|
||||
import { Loader } from '../../../../common/components/loader';
|
||||
|
@ -105,6 +106,17 @@ const ExceptionsViewerComponent = ({
|
|||
dispatch,
|
||||
] = useReducer(allExceptionItemsReducer(), { ...initialState });
|
||||
const { deleteExceptionItem, getExceptionListsItems } = useApi(services.http);
|
||||
const [supportedListTypes, setSupportedListTypes] = useState<ExceptionListTypeEnum[]>([]);
|
||||
|
||||
const [{ canUserCRUD, hasIndexWrite }] = useUserData();
|
||||
|
||||
useEffect((): void => {
|
||||
if (!canUserCRUD || !hasIndexWrite) {
|
||||
setSupportedListTypes([]);
|
||||
} else {
|
||||
setSupportedListTypes(availableListTypes);
|
||||
}
|
||||
}, [availableListTypes, canUserCRUD, hasIndexWrite]);
|
||||
|
||||
const setExceptions = useCallback(
|
||||
({
|
||||
|
@ -356,7 +368,7 @@ const ExceptionsViewerComponent = ({
|
|||
|
||||
<ExceptionsViewerHeader
|
||||
isInitLoading={isInitLoading}
|
||||
supportedListTypes={availableListTypes}
|
||||
supportedListTypes={supportedListTypes}
|
||||
detectionsListItems={totalDetectionsItems}
|
||||
endpointListItems={totalEndpointItems}
|
||||
onFilterChange={handleFilterChange}
|
||||
|
@ -374,6 +386,7 @@ const ExceptionsViewerComponent = ({
|
|||
/>
|
||||
|
||||
<ExceptionsViewerItems
|
||||
disableActions={!canUserCRUD || !hasIndexWrite}
|
||||
showEmpty={showEmpty}
|
||||
showNoResults={showNoResults}
|
||||
isInitLoading={isInitLoading}
|
||||
|
|
|
@ -35,25 +35,28 @@ export const useExceptionActions = ({
|
|||
const disabledAddException = !canUserCRUD || !hasIndexWrite;
|
||||
|
||||
const exceptionActionItems = useMemo(
|
||||
() => [
|
||||
<EuiContextMenuItem
|
||||
key="add-endpoint-exception-menu-item"
|
||||
data-test-subj="add-endpoint-exception-menu-item"
|
||||
disabled={disabledAddEndpointException}
|
||||
onClick={handleEndpointExceptionModal}
|
||||
>
|
||||
{ACTION_ADD_ENDPOINT_EXCEPTION}
|
||||
</EuiContextMenuItem>,
|
||||
() =>
|
||||
disabledAddException
|
||||
? []
|
||||
: [
|
||||
<EuiContextMenuItem
|
||||
key="add-endpoint-exception-menu-item"
|
||||
data-test-subj="add-endpoint-exception-menu-item"
|
||||
disabled={disabledAddEndpointException}
|
||||
onClick={handleEndpointExceptionModal}
|
||||
>
|
||||
{ACTION_ADD_ENDPOINT_EXCEPTION}
|
||||
</EuiContextMenuItem>,
|
||||
|
||||
<EuiContextMenuItem
|
||||
key="add-exception-menu-item"
|
||||
data-test-subj="add-exception-menu-item"
|
||||
disabled={disabledAddException}
|
||||
onClick={handleDetectionExceptionModal}
|
||||
>
|
||||
{ACTION_ADD_EXCEPTION}
|
||||
</EuiContextMenuItem>,
|
||||
],
|
||||
<EuiContextMenuItem
|
||||
key="add-exception-menu-item"
|
||||
data-test-subj="add-exception-menu-item"
|
||||
disabled={disabledAddException}
|
||||
onClick={handleDetectionExceptionModal}
|
||||
>
|
||||
{ACTION_ADD_EXCEPTION}
|
||||
</EuiContextMenuItem>,
|
||||
],
|
||||
[
|
||||
disabledAddEndpointException,
|
||||
disabledAddException,
|
||||
|
|
|
@ -18,6 +18,9 @@ import { mockTimelines } from '../../../common/mock/mock_timelines_plugin';
|
|||
import { createStartServicesMock } from '../../../common/lib/kibana/kibana_react.mock';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
|
||||
jest.mock('../user_info', () => ({
|
||||
useUserData: jest.fn().mockReturnValue([{ canUserCRUD: true, hasIndexWrite: true }]),
|
||||
}));
|
||||
jest.mock('../../../common/hooks/endpoint/use_isolate_privileges', () => ({
|
||||
useIsolationPrivileges: jest.fn().mockReturnValue({ isAllowed: true }),
|
||||
}));
|
||||
|
|
|
@ -12,6 +12,10 @@ import { TestProviders, mockTimelineModel, mockTimelineData } from '../../../../
|
|||
import { Actions } from '.';
|
||||
import { mockTimelines } from '../../../../../common/mock/mock_timelines_plugin';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features';
|
||||
|
||||
jest.mock('../../../../../detections/components/user_info', () => ({
|
||||
useUserData: jest.fn().mockReturnValue([{ canUserCRUD: true, hasIndexWrite: true }]),
|
||||
}));
|
||||
jest.mock('../../../../../common/hooks/use_experimental_features', () => ({
|
||||
useIsExperimentalFeatureEnabled: jest.fn().mockReturnValue(false),
|
||||
}));
|
||||
|
|
|
@ -166,8 +166,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
.expect(200);
|
||||
});
|
||||
|
||||
// Tests in development
|
||||
it.skip('should delete a single list referenced within an exception list item if ignoreReferences=true', async () => {
|
||||
it('should delete a single list referenced within an exception list item if ignoreReferences=true', async () => {
|
||||
// create a list
|
||||
const { body: valueListBody } = await supertest
|
||||
.post(LIST_URL)
|
||||
|
@ -207,8 +206,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
.expect(409);
|
||||
});
|
||||
|
||||
// Tests in development
|
||||
it.skip('should delete a single list referenced within an exception list item and referenced exception list items if deleteReferences=true', async () => {
|
||||
it('should delete a single list referenced within an exception list item and referenced exception list items if deleteReferences=true', async () => {
|
||||
// create a list
|
||||
const { body: valueListBody } = await supertest
|
||||
.post(LIST_URL)
|
||||
|
@ -241,6 +239,13 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
})
|
||||
.expect(200);
|
||||
|
||||
// sanity check
|
||||
await supertest
|
||||
.get(`${LIST_ITEM_URL}/_find?list_id=${LIST_ID}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// delete that list by its auto-generated id and delete referenced list items
|
||||
const deleteListBody = await supertest
|
||||
.delete(`${LIST_URL}?id=${valueListBody.id}&ignoreReferences=true`)
|
||||
|
@ -253,7 +258,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
.get(`${LIST_ITEM_URL}/_find?list_id=${LIST_ID}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
.expect(404);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,8 +18,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
const spacesService = getService('spaces');
|
||||
const supertestWithoutAuth = getService('supertestWithoutAuth');
|
||||
|
||||
// FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/88302
|
||||
describe.skip('read_list_privileges', () => {
|
||||
describe('read_list_privileges', () => {
|
||||
const space1Id = 'space_1';
|
||||
|
||||
const user1 = {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue