From e767ef47d3723c8a6c0a62aa489126f7673e347a Mon Sep 17 00:00:00 2001 From: Candace Park <56409205+parkiino@users.noreply.github.com> Date: Tue, 11 Jun 2024 18:03:02 -0400 Subject: [PATCH] [Security Solution][Endpoint Exceptions] Wildcard warning with IS operator for endpoint exceptions creation/editing (#182903) ## Summary - [x] Adds a warning message under the value, a callout and a confirmation warning modal to endpoint exceptions if an entry contains the "IS" operator with a wildcard value - [x] Unit Tests # Screenshots ![image](https://github.com/elastic/kibana/assets/56409205/d28b093f-77a1-4266-865f-657826879d0c) ![image](https://github.com/elastic/kibana/assets/56409205/70646034-73eb-4f7b-a84b-afaf4d32561c) --------- Co-authored-by: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../src/field_value_match/index.tsx | 4 +- .../index.tsx | 2 +- .../src/helpers/index.test.ts | 41 +++++++++++++++- .../src/helpers/index.ts | 22 ++++++++- .../src/path_validations/index.test.ts | 2 +- .../src/path_validations/index.ts | 16 +++++-- .../components/builder/entry_renderer.tsx | 5 +- .../add_exception_flyout/index.test.tsx | 26 ++++++++++ .../components/add_exception_flyout/index.tsx | 44 +++++++++++++++-- .../add_exception_flyout/reducer.ts | 16 ++++++- .../edit_exception_flyout/index.test.tsx | 26 ++++++++++ .../edit_exception_flyout/index.tsx | 48 +++++++++++++++++-- .../edit_exception_flyout/reducer.ts | 12 +++++ .../rule_exceptions/utils/translations.ts | 14 ++++++ .../public/management/common/translations.ts | 2 +- .../event_filters/view/components/form.tsx | 25 ++++------ .../pages/trusted_apps/view/translations.ts | 2 +- 17 files changed, 271 insertions(+), 36 deletions(-) diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx index 03604343f5d2..07b258deaae4 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx @@ -39,6 +39,7 @@ const BOOLEAN_OPTIONS = [ ]; const SINGLE_SELECTION = { asPlainText: true }; + type Warning = string | React.ReactNode; interface AutocompleteFieldMatchProps { @@ -152,9 +153,10 @@ export const AutocompleteFieldMatchComponent: React.FC {

diff --git a/packages/kbn-securitysolution-list-utils/src/helpers/index.test.ts b/packages/kbn-securitysolution-list-utils/src/helpers/index.test.ts index 6e06731798cc..0da36d21f405 100644 --- a/packages/kbn-securitysolution-list-utils/src/helpers/index.test.ts +++ b/packages/kbn-securitysolution-list-utils/src/helpers/index.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { getMappingConflictsInfo, fieldSupportsMatches } from '.'; +import { getMappingConflictsInfo, fieldSupportsMatches, hasWrongOperatorWithWildcard } from '.'; describe('Helpers', () => { describe('getMappingConflictsInfo', () => { @@ -181,4 +181,43 @@ describe('Helpers', () => { ).toBeFalsy(); }); }); + describe('hasWrongOperatorWithWildcard', () => { + test('it returns true if there is at least one exception entry with a wildcard and the wrong operator', () => { + expect( + hasWrongOperatorWithWildcard([ + { + description: '', + name: '', + type: 'simple', + entries: [{ type: 'match', value: 'withwildcard*', field: '', operator: 'included' }], + }, + ]) + ).toBeTruthy(); + expect( + hasWrongOperatorWithWildcard([ + { + description: '', + name: '', + type: 'simple', + entries: [{ type: 'match', value: 'withwildcard?', field: '', operator: 'included' }], + }, + ]) + ).toBeTruthy(); + }); + test('it returns false if there are no exception entries with a wildcard and the wrong operator', () => { + expect( + hasWrongOperatorWithWildcard([ + { + description: '', + name: '', + type: 'simple', + entries: [ + { type: 'match', value: 'nowildcard', field: '', operator: 'excluded' }, + { type: 'wildcard', value: 'withwildcard*?', field: '', operator: 'included' }, + ], + }, + ]) + ).toBeFalsy(); + }); + }); }); diff --git a/packages/kbn-securitysolution-list-utils/src/helpers/index.ts b/packages/kbn-securitysolution-list-utils/src/helpers/index.ts index bb08dd49887e..433aa62487b1 100644 --- a/packages/kbn-securitysolution-list-utils/src/helpers/index.ts +++ b/packages/kbn-securitysolution-list-utils/src/helpers/index.ts @@ -7,7 +7,11 @@ */ import { v4 as uuidv4 } from 'uuid'; -import { addIdToItem, removeIdFromItem } from '@kbn/securitysolution-utils'; +import { + addIdToItem, + removeIdFromItem, + validateHasWildcardWithWrongOperator, +} from '@kbn/securitysolution-utils'; import { validate } from '@kbn/securitysolution-io-ts-utils'; import { CreateExceptionListItemSchema, @@ -1021,3 +1025,19 @@ export const getMappingConflictsInfo = (field: DataViewField): FieldConflictsInf } return conflicts; }; + +/** + * Given an exceptions list, determine if any entries have an "IS" operator with a wildcard value + */ +export const hasWrongOperatorWithWildcard = ( + items: ExceptionsBuilderReturnExceptionItem[] +): boolean => { + return items[0]?.entries.some((e) => { + if (e.type !== 'list' && 'value' in e) { + return validateHasWildcardWithWrongOperator({ + operator: e.type, + value: e.value, + }); + } + }); +}; diff --git a/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts b/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts index b0ca96642c82..f768b78b932f 100644 --- a/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts +++ b/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts @@ -11,10 +11,10 @@ import { hasSimpleExecutableName, OperatingSystem, ConditionEntryField, + validateWildcardInput, validateHasWildcardWithWrongOperator, validatePotentialWildcardInput, validateFilePathInput, - validateWildcardInput, WILDCARD_WARNING, FILEPATH_WARNING, } from '.'; diff --git a/packages/kbn-securitysolution-utils/src/path_validations/index.ts b/packages/kbn-securitysolution-utils/src/path_validations/index.ts index 6c0798c7ffe2..2c5505f90d74 100644 --- a/packages/kbn-securitysolution-utils/src/path_validations/index.ts +++ b/packages/kbn-securitysolution-utils/src/path_validations/index.ts @@ -101,9 +101,17 @@ export const validateFilePathInput = ({ } }; -export const validateWildcardInput = (value?: string): string | undefined => { - if (/[*?]/.test(value ?? '')) { - return WILDCARD_WARNING; +export const validateWildcardInput = (value: string | string[]): string | undefined => { + const wildcardRegex = /[*?]/; + if (Array.isArray(value)) { + const doesAnyValueContainWildcardInput = value.some((v) => wildcardRegex.test(v)); + if (doesAnyValueContainWildcardInput) { + return WILDCARD_WARNING; + } + } else { + if (wildcardRegex.test(value)) { + return WILDCARD_WARNING; + } } }; @@ -112,7 +120,7 @@ export const validateHasWildcardWithWrongOperator = ({ value, }: { operator: TrustedAppEntryTypes | EventFiltersTypes; - value: string; + value: string | string[]; }): boolean => { if (operator !== 'wildcard' && validateWildcardInput(value)) { return true; diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx index 52075f49cb24..7ac354ed12ce 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx @@ -137,9 +137,10 @@ export const BuilderEntryItem: React.FC = ({ ([newOperator]: OperatorOption[]): void => { const { updatedEntry, index } = getEntryOnOperatorChange(entry, newOperator); handleError(false); + handleWarning(false); onChange(updatedEntry, index); }, - [onChange, entry, handleError] + [onChange, entry, handleError, handleWarning] ); const handleFieldMatchValueChange = useCallback( @@ -420,7 +421,7 @@ export const BuilderEntryItem: React.FC = ({ const value = typeof entry.value === 'string' ? entry.value : undefined; const fieldMatchWarning = /[*?]/.test(value ?? '') ? getWildcardWithIsOperatorWarning() - : ''; + : undefined; return ( { it('should NOT display the eql sequence callout', () => { expect(wrapper.find('[data-test-subj="eqlSequenceCallout"]').exists()).not.toBeTruthy(); }); + + it('should show a warning callout if wildcard is used', async () => { + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => + callProps.onChange({ + exceptionItems: [ + { + ...getExceptionListItemSchemaMock(), + entries: [ + { + field: 'event.category', + operator: 'included', + type: 'match', + value: 'wildcardvalue*?', + }, + ], + }, + ], + }) + ); + + wrapper.update(); + expect( + wrapper.find('[data-test-subj="wildcardWithWrongOperatorCallout"]').exists() + ).toBeTruthy(); + }); }); describe('alert data is passed in', () => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.tsx index 2a6b5c9523cf..a16fa6677b57 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { memo, useEffect, useCallback, useMemo, useReducer } from 'react'; +import React, { memo, useEffect, useCallback, useMemo, useReducer, useState } from 'react'; import styled, { css } from 'styled-components'; import { isEmpty } from 'lodash/fp'; @@ -30,11 +30,13 @@ import { import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import type { OsTypeArray, ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { hasWrongOperatorWithWildcard } from '@kbn/securitysolution-list-utils'; import type { ExceptionsBuilderExceptionItem, ExceptionsBuilderReturnExceptionItem, } from '@kbn/securitysolution-list-utils'; +import { WildCardWithWrongOperatorCallout } from '@kbn/securitysolution-exception-list-components'; import type { Moment } from 'moment'; import type { Status } from '../../../../../common/api/detection_engine'; import * as i18n from './translations'; @@ -44,6 +46,7 @@ import { retrieveAlertOsTypes, getPrepopulatedRuleExceptionWithHighlightFields, } from '../../utils/helpers'; +import { RULE_EXCEPTION, ENDPOINT_EXCEPTION } from '../../utils/translations'; import type { AlertData } from '../../utils/types'; import { initialState, createExceptionItemsReducer } from './reducer'; import { ExceptionsFlyoutMeta } from '../flyout_components/item_meta_form'; @@ -58,6 +61,8 @@ import { useCloseAlertsFromExceptions } from '../../logic/use_close_alerts'; import { ruleTypesThatAllowLargeValueLists } from '../../utils/constants'; import { useInvalidateFetchRuleByIdQuery } from '../../../rule_management/api/hooks/use_fetch_rule_by_id_query'; import { ExceptionsExpireTime } from '../flyout_components/expire_time'; +import { CONFIRM_WARNING_MODAL_LABELS } from '../../../../management/common/translations'; +import { ArtifactConfirmModal } from '../../../../management/components/artifact_list_page/components/artifact_confirm_modal'; const SectionHeader = styled(EuiTitle)` ${() => css` @@ -117,6 +122,7 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({ onConfirm, }: AddExceptionFlyoutProps) { const { euiTheme } = useEuiTheme(); + const [showConfirmModal, setShowConfirmModal] = useState(false); const { isLoading, indexPatterns, getExtendedFields } = useFetchIndexPatterns(rules); const [isSubmitting, submitNewExceptionItems] = useAddNewExceptionItems(); const [isClosingAlerts, closeAlerts] = useCloseAlertsFromExceptions(); @@ -165,6 +171,7 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({ errorSubmitting, expireTime, expireErrorExists, + wildcardWarningExists, }, dispatch, ] = useReducer(createExceptionItemsReducer(), { @@ -193,6 +200,10 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({ const setExceptionItemsToAdd = useCallback( (items: ExceptionsBuilderReturnExceptionItem[]): void => { + dispatch({ + type: 'setWildcardWithWrongOperator', + warningExists: hasWrongOperatorWithWildcard(items), + }); dispatch({ type: 'setExceptionItems', items, @@ -380,7 +391,7 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({ return hasAlertData ? retrieveAlertOsTypes(alertData) : selectedOs ? [...selectedOs] : []; }, [hasAlertData, alertData, selectedOs]); - const handleOnSubmit = useCallback(async (): Promise => { + const submitException = useCallback(async (): Promise => { if (submitNewExceptionItems == null) return; try { @@ -451,6 +462,14 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({ expireTime, ]); + const handleOnSubmit = useCallback(() => { + if (wildcardWarningExists) { + setShowConfirmModal(true); + } else { + return submitException(); + } + }, [wildcardWarningExists, submitException]); + const isSubmitButtonDisabled = useMemo( (): boolean => isSubmitting || @@ -499,6 +518,24 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({ prefix: 'exceptionFlyoutTitle', }); + const confirmModal = useMemo(() => { + const { title, body, confirmButton, cancelButton } = CONFIRM_WARNING_MODAL_LABELS( + listType === ExceptionListTypeEnum.ENDPOINT ? ENDPOINT_EXCEPTION : RULE_EXCEPTION + ); + + return ( + setShowConfirmModal(false)} + data-test-subj="artifactConfirmModal" + /> + ); + }, [listType, submitException]); + return ( - + {wildcardWarningExists && } {listType !== ExceptionListTypeEnum.ENDPOINT && !sharedListToAddTo?.length && ( <> @@ -639,6 +676,7 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({ + {showConfirmModal && confirmModal} ); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/reducer.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/reducer.ts index ec8040d1fe7c..01b0ce85b45d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/reducer.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/reducer.ts @@ -34,6 +34,7 @@ export interface State { errorSubmitting: Error | null; expireTime: Moment | undefined; expireErrorExists: boolean; + wildcardWarningExists: boolean; } export const initialState: State = { @@ -55,6 +56,7 @@ export const initialState: State = { errorSubmitting: null, expireTime: undefined, expireErrorExists: false, + wildcardWarningExists: false, }; export type Action = @@ -129,11 +131,15 @@ export type Action = | { type: 'setExpireError'; errorExists: boolean; + } + | { + type: 'setWildcardWithWrongOperator'; + warningExists: boolean; }; export const createExceptionItemsReducer = () => - /* eslint complexity: ["error", 21]*/ + /* eslint complexity: ["error", 22]*/ (state: State, action: Action): State => { switch (action.type) { case 'setExceptionItemMeta': { @@ -171,6 +177,13 @@ export const createExceptionItemsReducer = itemConditionValidationErrorExists: errorExists, }; } + case 'setWildcardWithWrongOperator': { + const { warningExists } = action; + return { + ...state, + wildcardWarningExists: warningExists, + }; + } case 'setComment': { const { comment } = action; @@ -250,7 +263,6 @@ export const createExceptionItemsReducer = } case 'setListType': { const { listType } = action; - return { ...state, listType, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.test.tsx index 077befdad52b..8fc6ddaa7d9b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.test.tsx @@ -297,6 +297,32 @@ describe('When the edit exception modal is opened', () => { it('should NOT display the eql sequence callout', () => { expect(wrapper.find('[data-test-subj="eqlSequenceCallout"]').exists()).not.toBeTruthy(); }); + + it('should show a warning callout if wildcard is used', async () => { + const callProps = mockGetExceptionBuilderComponentLazy.mock.calls[0][0]; + await waitFor(() => + callProps.onChange({ + exceptionItems: [ + { + ...getExceptionListItemSchemaMock(), + entries: [ + { + field: 'event.category', + operator: 'included', + type: 'match', + value: 'wildcardvalue?', + }, + ], + }, + ], + }) + ); + + wrapper.update(); + expect( + wrapper.find('[data-test-subj="wildcardWithWrongOperatorCallout"]').exists() + ).toBeTruthy(); + }); }); describe('when exception entry fields and index allow user to bulk close', () => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.tsx index 6470db5c9b4a..b620814ee3fe 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.tsx @@ -6,7 +6,7 @@ */ import { isEmpty } from 'lodash/fp'; -import React, { useCallback, useEffect, useMemo, useReducer } from 'react'; +import React, { useCallback, useEffect, useMemo, useReducer, useState } from 'react'; import styled, { css } from 'styled-components'; import { EuiButton, @@ -32,8 +32,11 @@ import { ExceptionListTypeEnum, } from '@kbn/securitysolution-io-ts-list-types'; +import { hasWrongOperatorWithWildcard } from '@kbn/securitysolution-list-utils'; import type { ExceptionsBuilderReturnExceptionItem } from '@kbn/securitysolution-list-utils'; +import { WildCardWithWrongOperatorCallout } from '@kbn/securitysolution-exception-list-components'; + import type { Moment } from 'moment'; import moment from 'moment'; import { @@ -58,7 +61,10 @@ import { createExceptionItemsReducer } from './reducer'; import { useEditExceptionItems } from './use_edit_exception'; import * as i18n from './translations'; +import { RULE_EXCEPTION, ENDPOINT_EXCEPTION } from '../../utils/translations'; import { ExceptionsExpireTime } from '../flyout_components/expire_time'; +import { CONFIRM_WARNING_MODAL_LABELS } from '../../../../management/common/translations'; +import { ArtifactConfirmModal } from '../../../../management/components/artifact_list_page/components/artifact_confirm_modal'; interface EditExceptionFlyoutProps { list: ExceptionListSchema; @@ -125,6 +131,7 @@ const EditExceptionFlyoutComponent: React.FC = ({ entryErrorExists, expireTime, expireErrorExists, + wildcardWarningExists, }, dispatch, ] = useReducer(createExceptionItemsReducer(), { @@ -138,6 +145,7 @@ const EditExceptionFlyoutComponent: React.FC = ({ entryErrorExists: false, expireTime: itemToEdit.expire_time !== undefined ? moment(itemToEdit.expire_time) : undefined, expireErrorExists: false, + wildcardWarningExists: false, }); const allowLargeValueLists = useMemo((): boolean => { @@ -152,6 +160,8 @@ const EditExceptionFlyoutComponent: React.FC = ({ } }, [rule]); + const [showConfirmModal, setShowConfirmModal] = useState(wildcardWarningExists); + const [isLoadingReferences, referenceFetchError, ruleReferences, fetchReferences] = useFindExceptionListReferences(); @@ -172,6 +182,10 @@ const EditExceptionFlyoutComponent: React.FC = ({ * */ const setExceptionItemsToAdd = useCallback( (items: ExceptionsBuilderReturnExceptionItem[]): void => { + dispatch({ + type: 'setWildcardWithWrongOperator', + warningExists: hasWrongOperatorWithWildcard(items), + }); dispatch({ type: 'setExceptionItems', items, @@ -281,7 +295,7 @@ const EditExceptionFlyoutComponent: React.FC = ({ [] ); - const handleSubmit = useCallback(async (): Promise => { + const handleSubmitException = useCallback(async (): Promise => { if (submitEditExceptionItems == null) return; try { @@ -335,6 +349,14 @@ const EditExceptionFlyoutComponent: React.FC = ({ expireTime, ]); + const handleOnSubmit = useCallback(() => { + if (wildcardWarningExists) { + setShowConfirmModal(true); + } else { + return handleSubmitException(); + } + }, [wildcardWarningExists, handleSubmitException]); + const editExceptionMessage = useMemo( () => listType === ExceptionListTypeEnum.ENDPOINT @@ -367,6 +389,24 @@ const EditExceptionFlyoutComponent: React.FC = ({ prefix: 'exceptionFlyoutTitle', }); + const confirmModal = useMemo(() => { + const { title, body, confirmButton, cancelButton } = CONFIRM_WARNING_MODAL_LABELS( + listType === ExceptionListTypeEnum.ENDPOINT ? ENDPOINT_EXCEPTION : RULE_EXCEPTION + ); + + return ( + setShowConfirmModal(false)} + data-test-subj="artifactConfirmModal" + /> + ); + }, [listType, handleSubmitException]); + return ( = ({ onSetErrorExists={setConditionsValidationError} getExtendedFields={getExtendedFields} /> + {wildcardWarningExists && } {!openedFromListDetailPage && listType === ExceptionListTypeEnum.DETECTION && ( <> @@ -466,7 +507,7 @@ const EditExceptionFlyoutComponent: React.FC = ({ @@ -474,6 +515,7 @@ const EditExceptionFlyoutComponent: React.FC = ({ + {showConfirmModal && confirmModal} ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/reducer.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/reducer.ts index e6dee3af1657..351af2090029 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/reducer.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/reducer.ts @@ -19,6 +19,7 @@ export interface State { entryErrorExists: boolean; expireTime: Moment | undefined; expireErrorExists: boolean; + wildcardWarningExists: boolean; } export type Action = @@ -61,6 +62,10 @@ export type Action = | { type: 'setExpireError'; errorExists: boolean; + } + | { + type: 'setWildcardWithWrongOperator'; + warningExists: boolean; }; export const createExceptionItemsReducer = @@ -150,6 +155,13 @@ export const createExceptionItemsReducer = expireErrorExists: errorExists, }; } + case 'setWildcardWithWrongOperator': { + const { warningExists } = action; + return { + ...state, + wildcardWarningExists: warningExists, + }; + } default: return state; } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/translations.ts index 012f4e677a5b..cfa7f54fcb5e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/translations.ts @@ -141,3 +141,17 @@ export const ERROR_FETCHING_REFERENCES_TITLE = i18n.translate( defaultMessage: 'Error fetching exception references', } ); + +export const RULE_EXCEPTION = i18n.translate( + 'xpack.securitySolution.ruleExceptions.addException.ruleException', + { + defaultMessage: 'rule exception', + } +); + +export const ENDPOINT_EXCEPTION = i18n.translate( + 'xpack.securitySolution.ruleExceptions.addException.endpointException', + { + defaultMessage: 'endpoint exception', + } +); diff --git a/x-pack/plugins/security_solution/public/management/common/translations.ts b/x-pack/plugins/security_solution/public/management/common/translations.ts index 628f8d5f9d42..469184e73a1f 100644 --- a/x-pack/plugins/security_solution/public/management/common/translations.ts +++ b/x-pack/plugins/security_solution/public/management/common/translations.ts @@ -217,7 +217,7 @@ export const CONFIRM_WARNING_MODAL_LABELS = (entryType: string) => { }), body: i18n.translate('xpack.securitySolution.artifacts.confirmWarningModal.body', { defaultMessage: - 'Using a "*" or a "?" in the value with the "IS" operator can make the entry ineffective. Change the operator to ‘matches’ to ensure wildcards run properly. Select “cancel” to revise your entry, or "add" to continue with the entry in its current state.', + 'Using a "*" or a "?" in the value with the "is" operator can make the entry ineffective. Change the operator to "matches" to ensure wildcards run properly. Select “Cancel” to revise your entry, or "Add" to continue with the entry in its current state.', }), confirmButton: i18n.translate( 'xpack.securitySolution.artifacts.confirmWarningModal.confirmButtonText', diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.tsx index e6d42f65e7a0..ee2ae2d5c6b6 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.tsx @@ -23,9 +23,12 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { EVENT_FILTERS_OPERATORS } from '@kbn/securitysolution-list-utils'; +import { + EVENT_FILTERS_OPERATORS, + hasWrongOperatorWithWildcard, +} from '@kbn/securitysolution-list-utils'; import { WildCardWithWrongOperatorCallout } from '@kbn/securitysolution-exception-list-components'; -import { OperatingSystem, validateHasWildcardWithWrongOperator } from '@kbn/securitysolution-utils'; +import { OperatingSystem } from '@kbn/securitysolution-utils'; import { getExceptionBuilderComponentLazy } from '@kbn/lists-plugin/public'; import type { OnChangeProps } from '@kbn/lists-plugin/public'; @@ -146,8 +149,10 @@ export const EventFiltersForm: React.FC(false); - const [hasWildcardWithWrongOperator, setHasWildcardWithWrongOperator] = - useState(false); + const [hasWildcardWithWrongOperator, setHasWildcardWithWrongOperator] = useState( + hasWrongOperatorWithWildcard([exception]) + ); + // This value has to be memoized to avoid infinite useEffect loop on useFetchIndex const indexNames = useMemo(() => [eventsIndexPattern], []); const [isIndexPatternLoading, { indexPatterns }] = useFetchIndex( @@ -425,17 +430,7 @@ export const EventFiltersForm: React.FC { - if ( - validateHasWildcardWithWrongOperator({ - operator: (e as EventFilterItemEntries[number]).type, - value: (e as EventFilterItemEntries[number]).value, - }) - ) { - setHasWildcardWithWrongOperator(true); - } - }); + setHasWildcardWithWrongOperator(hasWrongOperatorWithWildcard(arg.exceptionItems)); const updatedItem: Partial = arg.exceptionItems[0] !== undefined diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/translations.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/translations.ts index 115e4a9f3add..c1e544be537e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/translations.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/translations.ts @@ -156,7 +156,7 @@ export const INPUT_ERRORS = { ), wildcardWithWrongOperatorWarning: (index: number) => i18n.translate('xpack.securitySolution.trustedapps.create.conditionWrongOperatorMsg', { - defaultMessage: `[{row}] Using a '*' or a '?' in the value with the 'IS' operator can make the entry ineffective. Change the operator to 'matches' to ensure wildcards run properly.`, + defaultMessage: `[{row}] Using a "*" or a "?" in the value with the "is" operator can make the entry ineffective. Change the operator to "matches" to ensure wildcards run properly.`, values: { row: index + 1 }, }), wildcardWithWrongField: (index: number) =>