[Security Solution][Exceptions] - Fix stale linked rules count on manage rules save (#155108)

## Summary

Addresses https://github.com/elastic/kibana/issues/153195
This commit is contained in:
Yara Tercero 2023-04-20 11:23:15 -07:00 committed by GitHub
parent dd46350cac
commit ada91f9a5e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 68 additions and 15 deletions

View file

@ -14,7 +14,7 @@ import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../..
import { EXCEPTIONS_URL } from '../../../urls/navigation';
import {
deleteExceptionListWithRuleReference,
deleteExceptionListWithRuleReferenceByListId,
deleteExceptionListWithoutRuleReference,
exportExceptionList,
searchForExceptionList,
@ -79,7 +79,7 @@ describe('Exceptions Table', () => {
visitWithoutDateRange(EXCEPTIONS_URL);
waitForExceptionsTableToBeLoaded();
exportExceptionList();
exportExceptionList(getExceptionList1().list_id);
cy.wait('@export').then(({ response }) => {
cy.wrap(response?.body).should(
@ -168,7 +168,7 @@ describe('Exceptions Table', () => {
// just checking number of lists shown
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '2');
deleteExceptionListWithRuleReference();
deleteExceptionListWithRuleReferenceByListId(getExceptionList2().list_id);
// Using cy.contains because we do not care about the exact text,
// just checking number of lists shown

View file

@ -14,11 +14,13 @@ import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../..
import { EXCEPTIONS_URL } from '../../../urls/navigation';
import {
deleteExceptionListWithRuleReference,
deleteExceptionListWithRuleReferenceByListId,
deleteExceptionListWithoutRuleReference,
exportExceptionList,
waitForExceptionsTableToBeLoaded,
createSharedExceptionList,
linkRulesToExceptionList,
assertNumberLinkedRules,
} from '../../../tasks/exceptions_table';
import {
EXCEPTIONS_LIST_MANAGEMENT_NAME,
@ -46,6 +48,8 @@ describe('Manage shared exception list', () => {
esArchiverResetKibana();
login();
createRule(getNewRule({ name: 'Another rule' }));
// Create exception list associated with a rule
createExceptionList(getExceptionList2(), getExceptionList2().list_id).then((response) =>
createRule(
@ -76,7 +80,7 @@ describe('Manage shared exception list', () => {
it('Export exception list', function () {
cy.intercept(/(\/api\/exception_lists\/_export)/).as('export');
exportExceptionList();
exportExceptionList(getExceptionList1().list_id);
cy.wait('@export').then(({ response }) => {
cy.wrap(response?.body).should(
@ -91,6 +95,12 @@ describe('Manage shared exception list', () => {
});
});
it('Link rules to shared exception list', function () {
assertNumberLinkedRules(getExceptionList2().list_id, '1');
linkRulesToExceptionList(getExceptionList2().list_id, 1);
assertNumberLinkedRules(getExceptionList2().list_id, '2');
});
it('Create exception list', function () {
createSharedExceptionList({ name: EXCEPTION_LIST_NAME, description: 'This is my list.' }, true);
@ -118,7 +128,7 @@ describe('Manage shared exception list', () => {
// just checking number of lists shown
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '3');
deleteExceptionListWithRuleReference();
deleteExceptionListWithRuleReferenceByListId(getExceptionList2().list_id);
// Using cy.contains because we do not care about the exact text,
// just checking number of lists shown

View file

@ -49,6 +49,9 @@ export const EXCEPTIONS_TABLE_SHOWING_LISTS = '[data-test-subj="showingException
export const EXCEPTIONS_TABLE_DELETE_BTN =
'[data-test-subj="sharedListOverflowCardActionItemDelete"]';
export const EXCEPTIONS_TABLE_LINK_RULES_BTN =
'[data-test-subj="sharedListOverflowCardActionItemLinkRules"]';
export const EXCEPTIONS_TABLE_EXPORT_MODAL_BTN =
'[data-test-subj="sharedListOverflowCardActionItemExport"]';
@ -149,6 +152,13 @@ export const CREATE_SHARED_EXCEPTION_LIST_DESCRIPTION_INPUT =
export const CREATE_SHARED_EXCEPTION_LIST_BTN =
'button[data-test-subj="exception-lists-form-create-shared"]';
export const exceptionsTableListManagementListContainerByListId = (listId: string) =>
`[data-test-subj="exceptionsManagementListCard-${listId}"]`;
export const LINKED_RULES_BADGE = '[data-test-subj="exceptionListCardLinkedRulesBadge"]';
export const MANAGE_RULES_SAVE = '[data-test-subj="manageListRulesSaveButton"]';
// Exception list management
export const EXCEPTIONS_LIST_MANAGEMENT_NAME =
'[data-test-subj="exceptionListManagementTitleText"]';

View file

@ -26,6 +26,11 @@ import {
EXCEPTIONS_LIST_MANAGEMENT_EDIT_MODAL_DESCRIPTION_INPUT,
EXCEPTIONS_LIST_EDIT_DETAILS_SAVE_BTN,
EXCEPTIONS_LIST_DETAILS_HEADER,
exceptionsTableListManagementListContainerByListId,
EXCEPTIONS_TABLE_LINK_RULES_BTN,
RULE_ACTION_LINK_RULE_SWITCH,
LINKED_RULES_BADGE,
MANAGE_RULES_SAVE,
} from '../screens/exceptions';
export const clearSearchSelection = () => {
@ -36,12 +41,30 @@ export const expandExceptionActions = () => {
cy.get(EXCEPTIONS_OVERFLOW_ACTIONS_BTN).first().click();
};
export const exportExceptionList = () => {
cy.get(EXCEPTIONS_OVERFLOW_ACTIONS_BTN).first().click();
export const exportExceptionList = (listId: string) => {
cy.get(exceptionsTableListManagementListContainerByListId(listId))
.find(EXCEPTIONS_OVERFLOW_ACTIONS_BTN)
.click();
cy.get(EXCEPTIONS_TABLE_EXPORT_MODAL_BTN).first().click();
cy.get(EXCEPTIONS_TABLE_EXPORT_CONFIRM_BTN).first().click();
};
export const assertNumberLinkedRules = (listId: string, numberOfRulesAsString: string) => {
cy.get(exceptionsTableListManagementListContainerByListId(listId))
.find(LINKED_RULES_BADGE)
.contains(numberOfRulesAsString);
};
export const linkRulesToExceptionList = (listId: string, ruleSwitch: number = 0) => {
cy.log(`Open link rules flyout for list_id: '${listId}'`);
cy.get(exceptionsTableListManagementListContainerByListId(listId))
.find(EXCEPTIONS_OVERFLOW_ACTIONS_BTN)
.click();
cy.get(EXCEPTIONS_TABLE_LINK_RULES_BTN).first().click();
cy.get(RULE_ACTION_LINK_RULE_SWITCH).eq(ruleSwitch).find('button').click();
cy.get(MANAGE_RULES_SAVE).first().click();
};
export const deleteExceptionListWithoutRuleReference = () => {
cy.get(EXCEPTIONS_OVERFLOW_ACTIONS_BTN).first().click();
cy.get(EXCEPTIONS_TABLE_DELETE_BTN).first().click();
@ -50,8 +73,10 @@ export const deleteExceptionListWithoutRuleReference = () => {
cy.get(EXCEPTIONS_TABLE_MODAL).should('not.exist');
};
export const deleteExceptionListWithRuleReference = () => {
cy.get(EXCEPTIONS_OVERFLOW_ACTIONS_BTN).last().click();
export const deleteExceptionListWithRuleReferenceByListId = (listId: string) => {
cy.get(exceptionsTableListManagementListContainerByListId(listId))
.find(EXCEPTIONS_OVERFLOW_ACTIONS_BTN)
.click();
cy.get(EXCEPTIONS_TABLE_DELETE_BTN).last().click();
cy.get(EXCEPTIONS_TABLE_MODAL).should('exist');
cy.get(EXCEPTIONS_TABLE_MODAL_CONFIRM_BTN).first().click();

View file

@ -102,7 +102,6 @@ export const ExceptionsListCard = memo<ExceptionsListCardProps>(
toggleAccordion,
openAccordionId,
menuActionItems,
listRulesCount,
listDescription,
exceptionItemsCount,
onEditExceptionItem,
@ -184,8 +183,11 @@ export const ExceptionsListCard = memo<ExceptionsListCardProps>(
<EuiFlexItem>
<TitleBadge title={i18n.EXCEPTIONS} badgeString={exceptionItemsCount} />
</EuiFlexItem>
<EuiFlexItem>
<TitleBadge title={i18n.RULES} badgeString={listRulesCount} />
<EuiFlexItem data-test-subj="exceptionListCardLinkedRulesBadge">
<TitleBadge
title={i18n.RULES}
badgeString={linkedRules.length.toString()}
/>
</EuiFlexItem>
<EuiFlexItem>
<HeaderMenu
@ -199,6 +201,7 @@ export const ExceptionsListCard = memo<ExceptionsListCardProps>(
</ListHeaderContainer>
</EuiPanel>
}
data-test-subj={`exceptionsManagementListCard-${listId}`}
>
<ExceptionPanel hasBorder>
<ListExceptionItems

View file

@ -77,6 +77,7 @@ export const ManageRules: FC<ManageRulesProps> = memo(
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj="manageListRulesSaveButton"
isLoading={showButtonLoader}
disabled={saveIsDisabled}
onClick={onSave}

View file

@ -340,6 +340,9 @@ export const useListDetailsView = (exceptionListId: string) => {
i18n.EXCEPTION_MANAGE_RULES_ERROR_DESCRIPTION
);
setShowManageButtonLoader(false);
})
.finally(() => {
initializeList();
});
} catch (err) {
handleErrorStatus(err);
@ -348,10 +351,11 @@ export const useListDetailsView = (exceptionListId: string) => {
list,
getRulesToAdd,
getRulesToRemove,
exceptionListId,
resetManageRulesAfterSaving,
handleErrorStatus,
exceptionListId,
invalidateFetchRuleByIdQuery,
handleErrorStatus,
initializeList,
]);
const onCancelManageRules = useCallback(() => {
setShowManageRulesFlyout(false);