From 57bf657fc15c9eb40853773ca5702ecae66453dd Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Tue, 20 Apr 2021 12:34:59 +0200 Subject: [PATCH 01/36] show operator dropdown for path field refs elastic/security-team/issues/543 --- .../common/endpoint/types/trusted_apps.ts | 6 ++- .../condition_entry_input/index.tsx | 43 ++++++++++++++++--- .../components/trusted_app_card/index.tsx | 4 +- .../pages/trusted_apps/view/translations.ts | 5 ++- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts index d36958c11d2a1..371f7848b6bb4 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts @@ -69,10 +69,14 @@ export enum ConditionEntryField { SIGNER = 'process.Ext.code_signature', } +export enum OperatorEntryField { + included = 'included', + wildcard_caseless = 'wildcard_caseless', +} export interface ConditionEntry { field: T; type: 'match'; - operator: 'included'; + operator: keyof typeof OperatorEntryField; value: string; } diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index f85f00810bc72..7371f6bace43a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -21,6 +21,7 @@ import { import { ConditionEntry, ConditionEntryField, + OperatorEntryField, OperatingSystem, } from '../../../../../../../common/endpoint/types'; @@ -28,7 +29,7 @@ import { CONDITION_FIELD_DESCRIPTION, CONDITION_FIELD_TITLE, ENTRY_PROPERTY_TITLES, - OPERATOR_TITLE, + OPERATOR_TITLES, } from '../../translations'; const ConditionEntryCell = memo<{ @@ -113,6 +114,18 @@ export const ConditionEntryInput = memo( ]; }, [os]); + const operatorOptions = useMemo>>(() => { + const dropDownOptions = [ + OperatorEntryField.included, + OperatorEntryField.wildcard_caseless, + ].map((e) => ({ + dropdownDisplay: OPERATOR_TITLES[e], + inputDisplay: OPERATOR_TITLES[e], + value: e, + })); + return dropDownOptions; + }, []); + const handleValueUpdate = useCallback>( (ev) => onChange({ ...entry, value: ev.target.value }, entry), [entry, onChange] @@ -123,6 +136,11 @@ export const ConditionEntryInput = memo( [entry, onChange] ); + const handleOperatorUpdate = useCallback( + (newOperator) => onChange({ ...entry, operator: newOperator }, entry), + [entry, onChange] + ); + const handleRemoveClick = useCallback(() => onRemove(entry), [entry, onRemove]); const handleValueOnBlur = useCallback(() => { @@ -149,11 +167,24 @@ export const ConditionEntryInput = memo( /> - - - - - + {entry.field === ConditionEntryField.PATH ? ( + + + + + + ) : ( + + + + + + )} truncateText: true, width: '20%', render(field: Entry['operator'], entry: Entry) { - return OPERATOR_TITLE[field]; + return OPERATOR_TITLES[field]; }, }, { 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 57ca80930ad7d..2778eb82534c8 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 @@ -52,10 +52,13 @@ export const CONDITION_FIELD_DESCRIPTION: { [K in ConditionEntryField]: string } ), }; -export const OPERATOR_TITLE: { [K in ConditionEntry['operator']]: string } = { included: i18n.translate('xpack.securitySolution.trustedapps.card.operator.includes', { +export const OPERATOR_TITLES: { [K in ConditionEntry['operator']]: string } = { defaultMessage: 'is', }), + wildcard_caseless: i18n.translate('xpack.securitySolution.trustedapps.card.operator.matches', { + defaultMessage: 'matches', + }), }; export const PROPERTY_TITLES: Readonly< From dd84507cffefb7900e01f525779d1b2434351ff0 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Tue, 20 Apr 2021 12:36:24 +0200 Subject: [PATCH 02/36] update translation to use consistent values refs elastic/security-team/issues/543 --- .../public/management/pages/trusted_apps/view/translations.ts | 2 +- x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) 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 2778eb82534c8..ef86e8f084a74 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 @@ -52,8 +52,8 @@ export const CONDITION_FIELD_DESCRIPTION: { [K in ConditionEntryField]: string } ), }; - included: i18n.translate('xpack.securitySolution.trustedapps.card.operator.includes', { export const OPERATOR_TITLES: { [K in ConditionEntry['operator']]: string } = { + included: i18n.translate('xpack.securitySolution.trustedapps.card.operator.is', { defaultMessage: 'is', }), wildcard_caseless: i18n.translate('xpack.securitySolution.trustedapps.card.operator.matches', { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index ec604eaf255cb..94e4dd08f3a2c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -20513,7 +20513,6 @@ "xpack.securitySolution.topN.closeButtonLabel": "閉じる", "xpack.securitySolution.topN.rawEventsSelectLabel": "未加工イベント", "xpack.securitySolution.trustedapps.aboutInfo": "パフォーマンスを改善したり、ホストで実行されている他のアプリケーションとの競合を解消したりするには、信頼できるアプリケーションを追加します。信頼できるアプリケーションは、Endpoint Securityを実行しているホストに適用されます。", - "xpack.securitySolution.trustedapps.card.operator.includes": "is", "xpack.securitySolution.trustedapps.card.removeButtonLabel": "削除", "xpack.securitySolution.trustedapps.create.conditionFieldValueRequiredMsg": "[{row}] フィールドエントリには値が必要です", "xpack.securitySolution.trustedapps.create.conditionRequiredMsg": "1つ以上のフィールド定義が必要です", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 729e32e11a5ff..d846a1a7702aa 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -20840,7 +20840,6 @@ "xpack.securitySolution.topN.closeButtonLabel": "关闭", "xpack.securitySolution.topN.rawEventsSelectLabel": "原始事件", "xpack.securitySolution.trustedapps.aboutInfo": "添加受信任的应用程序,以提高性能或缓解与主机上运行的其他应用程序的冲突。受信任的应用程序将应用于运行 Endpoint Security 的主机。", - "xpack.securitySolution.trustedapps.card.operator.includes": "是", "xpack.securitySolution.trustedapps.card.removeButtonLabel": "移除", "xpack.securitySolution.trustedapps.create.conditionFieldValueRequiredMsg": "[{row}] 字段条目必须包含值", "xpack.securitySolution.trustedapps.create.conditionRequiredMsg": "至少需要一个字段定义", From 9f722506ebc773fb4c880d92574a42c8d1d886eb Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Tue, 20 Apr 2021 15:32:38 +0200 Subject: [PATCH 03/36] update schema to validate path values refs elastic/security-team/issues/543 --- .../common/endpoint/schema/trusted_apps.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts index e582744e1a141..3c397257d3f79 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { ConditionEntry, ConditionEntryField, OperatingSystem } from '../types'; +import { ConditionEntry, ConditionEntryField, OperatingSystem, OperatorEntryField } from '../types'; import { getDuplicateFields, isValidHash } from '../service/trusted_apps/validations'; export const DeleteTrustedAppsRequestSchema = { @@ -30,7 +30,10 @@ export const GetTrustedAppsRequestSchema = { }; const ConditionEntryTypeSchema = schema.literal('match'); -const ConditionEntryOperatorSchema = schema.literal('included'); +const ConditionEntryOperatorSchema = schema.oneOf([ + schema.literal(OperatorEntryField.included), + schema.literal(OperatorEntryField.wildcard_caseless), +]); /* * A generic Entry schema to be used for a specific entry schema depending on the OS From fa9e3cec086cbf3095c9e1e7c95b363e2221eb47 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Tue, 20 Apr 2021 18:01:09 +0200 Subject: [PATCH 04/36] add tests for field and operator values refs elastic/security-team/issues/543 --- .../condition_entry_input/index.test.tsx | 37 +++++++++++++++---- .../condition_entry_input/index.tsx | 7 +++- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.test.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.test.tsx index 4e9ec3a0883a2..9d6c35d64b2d5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.test.tsx @@ -21,7 +21,7 @@ let onRemoveMock: jest.Mock; let onChangeMock: jest.Mock; let onVisitedMock: jest.Mock; -const entry: Readonly = { +const baseEntry: Readonly = { field: ConditionEntryField.HASH, type: 'match', operator: 'included', @@ -38,7 +38,8 @@ describe('Condition entry input', () => { const getElement = ( subject: string, os: OperatingSystem = OperatingSystem.WINDOWS, - isRemoveDisabled: boolean = false + isRemoveDisabled: boolean = false, + entry: ConditionEntry = baseEntry ) => ( { expect(onChangeMock).toHaveBeenCalledTimes(1); expect(onChangeMock).toHaveBeenCalledWith( { - ...entry, + ...baseEntry, field: { target: { value: field } }, }, - entry + baseEntry ); } ); @@ -77,7 +78,7 @@ describe('Condition entry input', () => { expect(onRemoveMock).toHaveBeenCalledTimes(0); element.find('[data-test-subj="testOnRemove-remove"]').first().simulate('click'); expect(onRemoveMock).toHaveBeenCalledTimes(1); - expect(onRemoveMock).toHaveBeenCalledWith(entry); + expect(onRemoveMock).toHaveBeenCalledWith(baseEntry); }); it('should not be able to call on remove for field input because disabled', () => { @@ -92,7 +93,7 @@ describe('Condition entry input', () => { expect(onVisitedMock).toHaveBeenCalledTimes(0); element.find('[data-test-subj="testOnVisited-value"]').first().simulate('blur'); expect(onVisitedMock).toHaveBeenCalledTimes(1); - expect(onVisitedMock).toHaveBeenCalledWith(entry); + expect(onVisitedMock).toHaveBeenCalledWith(baseEntry); }); it('should change value for field input', () => { @@ -105,10 +106,10 @@ describe('Condition entry input', () => { expect(onChangeMock).toHaveBeenCalledTimes(1); expect(onChangeMock).toHaveBeenCalledWith( { - ...entry, + ...baseEntry, value: 'new value', }, - entry + baseEntry ); }); @@ -138,4 +139,24 @@ describe('Condition entry input', () => { .props() as EuiSuperSelectProps; expect(superSelectProps.options.length).toBe(2); }); + + it('should have operator value selected when field is HASH', () => { + const element = shallow(getElement('testOperatorOptions')); + const inputField = element.find('[data-test-subj="testOperatorOptions-operator"]'); + expect(inputField.contains('is')); + }); + + it('should show operator dorpdown with two values when field is PATH', () => { + const element = shallow( + getElement('testOperatorOptions', undefined, undefined, { + ...baseEntry, + field: ConditionEntryField.PATH, + }) + ); + const superSelectProps = element + .find('[data-test-subj="testOperatorOptions-operator"]') + .first() + .props() as EuiSuperSelectProps; + expect(superSelectProps.options.length).toBe(2); + }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index 7371f6bace43a..e85c2129235e6 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -181,7 +181,12 @@ export const ConditionEntryInput = memo( ) : ( - + )} From 8c19290e83c032579395b34c9a975bb121ed6fab Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Wed, 21 Apr 2021 09:30:08 +0200 Subject: [PATCH 05/36] review changes refs elastic/security-team/issues/543 --- .../components/condition_entry_input/index.tsx | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index e85c2129235e6..9534097fb4de8 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -114,17 +114,13 @@ export const ConditionEntryInput = memo( ]; }, [os]); - const operatorOptions = useMemo>>(() => { - const dropDownOptions = [ - OperatorEntryField.included, - OperatorEntryField.wildcard_caseless, - ].map((e) => ({ - dropdownDisplay: OPERATOR_TITLES[e], - inputDisplay: OPERATOR_TITLES[e], - value: e, - })); - return dropDownOptions; - }, []); + const operatorOptions = (Object.keys(OperatorEntryField) as [ConditionEntry['operator']]).map( + (value) => ({ + dropdownDisplay: OPERATOR_TITLES[value], + inputDisplay: OPERATOR_TITLES[value], + value, + }) + ); const handleValueUpdate = useCallback>( (ev) => onChange({ ...entry, value: ev.target.value }, entry), From 1deab39453178fccd432fcdfde2a09f630e7611c Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Wed, 21 Apr 2021 10:09:43 +0200 Subject: [PATCH 06/36] update schema to enforce dropdown validation for PATH field refs elastic/security-team/issues/543 --- .../common/endpoint/schema/trusted_apps.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts index 3c397257d3f79..03cbe53f60320 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts @@ -30,10 +30,16 @@ export const GetTrustedAppsRequestSchema = { }; const ConditionEntryTypeSchema = schema.literal('match'); -const ConditionEntryOperatorSchema = schema.oneOf([ - schema.literal(OperatorEntryField.included), - schema.literal(OperatorEntryField.wildcard_caseless), -]); +// when field === PATH -> operator in ('included', 'wildcard_caseless') else operator === 'included' +const ConditionEntryOperatorSchema = schema.conditional( + schema.siblingRef('field'), + ConditionEntryField.PATH, + schema.oneOf([ + schema.literal(OperatorEntryField.included), + schema.literal(OperatorEntryField.wildcard_caseless), + ]), + schema.literal(OperatorEntryField.included) +); /* * A generic Entry schema to be used for a specific entry schema depending on the OS From baac4522ecc069a02fde022a92c484e1ca4acc5e Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Wed, 21 Apr 2021 11:17:01 +0200 Subject: [PATCH 07/36] add tests for schema updates refs 1deab394531 refs elastic/security-team/issues/543 --- .../endpoint/schema/trusted_apps.test.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts index 326795ae55662..23f1d678e332a 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts @@ -247,6 +247,30 @@ describe('When invoking Trusted Apps Schema', () => { expect(() => body.validate(bodyMsg)).not.toThrow(); }); + it('should validate `entry.operator` does not accept `wildcard_caseless` when field is NOT PATH', () => { + const bodyMsg = createNewTrustedApp({ + entries: [ + createConditionEntry({ + field: ConditionEntryField.HASH, + operator: 'wildcard_caseless', + }), + ], + }); + expect(() => body.validate(bodyMsg)).toThrow(); + }); + + it('should validate `entry.operator` accepts `wildcard_caseless` when field is PATH', () => { + const bodyMsg = createNewTrustedApp({ + entries: [ + createConditionEntry({ + field: ConditionEntryField.PATH, + operator: 'wildcard_caseless', + }), + ], + }); + expect(() => body.validate(bodyMsg)).not.toThrow(); + }); + it('should validate `entry.value` required', () => { const { value, ...entry } = createConditionEntry(); expect(() => body.validate(createNewTrustedApp({ entries: [entry] }))).toThrow(); From 5d9e848f67e468c1e7058663b93ea9b5d948f870 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Wed, 21 Apr 2021 13:22:33 +0200 Subject: [PATCH 08/36] optimise dropdown list for re-renders refs elastic/security-team/issues/543 --- .../view/components/condition_entry_input/index.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index 9534097fb4de8..fc422ea0faa0c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -114,13 +114,15 @@ export const ConditionEntryInput = memo( ]; }, [os]); - const operatorOptions = (Object.keys(OperatorEntryField) as [ConditionEntry['operator']]).map( - (value) => ({ + // use a memoized callback to + // limit list iteration for re-renders + const operatorOptions = useMemo>>(() => { + return (Object.keys(OperatorEntryField) as [ConditionEntry['operator']]).map((value) => ({ dropdownDisplay: OPERATOR_TITLES[value], inputDisplay: OPERATOR_TITLES[value], value, - }) - ); + })); + }, []); const handleValueUpdate = useCallback>( (ev) => onChange({ ...entry, value: ev.target.value }, entry), From f657b8058d901155295330ceb75c2292efa4722f Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Thu, 22 Apr 2021 10:20:32 +0200 Subject: [PATCH 09/36] align input fields and keep alignments when resized refs elastic/security-team/issues/543 --- .../condition_entry_input/index.tsx | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index fc422ea0faa0c..dd843df3a4858 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -6,6 +6,7 @@ */ import React, { ChangeEventHandler, memo, useCallback, useMemo } from 'react'; +import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; import { EuiButtonIcon, @@ -66,6 +67,14 @@ export interface ConditionEntryInputProps { 'data-test-subj'?: string; } +// adding a style prop on EuiFlexGroup works only partially +// and for some odd reason garbles up gridTemplateAreas entry +const StyledEuiFlexGroup = styled(EuiFlexGroup)` + display: grid; + grid-template-columns: 25% 25% 45% 5%; + grid-template-areas: 'field operator value remove'; +`; + export const ConditionEntryInput = memo( ({ os, @@ -148,14 +157,14 @@ export const ConditionEntryInput = memo( }, [entry, onVisited]); return ( - - + ( {entry.field === ConditionEntryField.PATH ? ( - + ( ) : ( - + ( )} - + ( /> - + {/* Unicode `nbsp` is used below so that Remove button is property displayed */} ( /> - + ); } ); From 2ac56ee839342c520928487b4a49f25938fa08ca Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Thu, 22 Apr 2021 17:24:01 +0200 Subject: [PATCH 10/36] correctly enter operator data on trusted app CRUD refs elastic/security-team/issues/543 --- .../lists/common/schemas/common/schemas.ts | 3 +- .../endpoint/routes/trusted_apps/mapping.ts | 66 ++++++++++++++++--- .../detection_engine/signals/filters/types.ts | 2 +- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/lists/common/schemas/common/schemas.ts b/x-pack/plugins/lists/common/schemas/common/schemas.ts index f261e4e3eefa6..d702ef157ca43 100644 --- a/x-pack/plugins/lists/common/schemas/common/schemas.ts +++ b/x-pack/plugins/lists/common/schemas/common/schemas.ts @@ -276,11 +276,12 @@ export type CursorOrUndefined = t.TypeOf; export const namespace_type = DefaultNamespace; export const operatorIncluded = t.keyof({ included: null }); -export const operator = t.keyof({ excluded: null, included: null }); +export const operator = t.keyof({ excluded: null, included: null, wildcard_caseless: null }); export type Operator = t.TypeOf; export enum OperatorEnum { INCLUDED = 'included', EXCLUDED = 'excluded', + WILDCARD_CASELESS = 'wildcard_caseless', } export enum OperatorTypeEnum { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts index c6048e5725c88..22d87e888f05c 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts @@ -26,6 +26,7 @@ import { EffectScope, NewTrustedApp, OperatingSystem, + OperatorEntryField, TrustedApp, UpdateTrustedApp, } from '../../../../common/endpoint/types'; @@ -51,11 +52,12 @@ const filterUndefined = (list: Array): T[] => { return list.filter((item: T | undefined): item is T => item !== undefined); }; -export const createConditionEntry = ( +export const createConditionEntry = ( field: T, + operator: O, value: string ): ConditionEntry => { - return { field, value, type: 'match', operator: 'included' }; + return { field, value, type: 'match', operator }; }; export const tagsToEffectScope = (tags: string[]): EffectScope => { @@ -78,12 +80,37 @@ export const entriesToConditionEntriesMap = (entries: EntriesArray): ConditionEn if (entry.field.startsWith('process.hash') && entry.type === 'match') { return { ...result, - [ConditionEntryField.HASH]: createConditionEntry(ConditionEntryField.HASH, entry.value), + [ConditionEntryField.HASH]: createConditionEntry( + ConditionEntryField.HASH, + OperatorEntryField.included, + entry.value + ), }; - } else if (entry.field === 'process.executable.caseless' && entry.type === 'match') { + } else if ( + entry.field === 'process.executable.caseless' && + entry.type === 'match' && + entry.operator === OperatorEntryField.wildcard_caseless + ) { return { ...result, - [ConditionEntryField.PATH]: createConditionEntry(ConditionEntryField.PATH, entry.value), + [ConditionEntryField.PATH]: createConditionEntry( + ConditionEntryField.PATH, + OperatorEntryField.wildcard_caseless, + entry.value + ), + }; + } else if ( + entry.field === 'process.executable.caseless' && + entry.type === 'match' && + entry.operator === OperatorEntryField.included + ) { + return { + ...result, + [ConditionEntryField.PATH]: createConditionEntry( + ConditionEntryField.PATH, + OperatorEntryField.included, + entry.value + ), }; } else if (entry.field === 'process.Ext.code_signature' && entry.type === 'nested') { const subjectNameCondition = entry.entries.find((subEntry): subEntry is EntryMatch => { @@ -95,6 +122,7 @@ export const entriesToConditionEntriesMap = (entries: EntriesArray): ConditionEn ...result, [ConditionEntryField.SIGNER]: createConditionEntry( ConditionEntryField.SIGNER, + OperatorEntryField.included, subjectNameCondition.value ), }; @@ -165,8 +193,12 @@ const hashType = (hash: string): 'md5' | 'sha256' | 'sha1' | undefined => { } }; -export const createEntryMatch = (field: string, value: string): EntryMatch => { - return { field, value, type: 'match', operator: 'included' }; +export const createEntryMatch = ( + field: string, + operator: ConditionEntry['operator'], + value: string +): EntryMatch => { + return { field, value, type: 'match', operator }; }; export const createEntryNested = (field: string, entries: NestedEntriesArray): EntryNested => { @@ -186,15 +218,29 @@ export const conditionEntriesToEntries = (conditionEntries: ConditionEntry[]): E if (conditionEntry.field === ConditionEntryField.HASH) { return createEntryMatch( `process.hash.${hashType(conditionEntry.value)}`, + OperatorEntryField.included, conditionEntry.value.toLowerCase() ); } else if (conditionEntry.field === ConditionEntryField.SIGNER) { return createEntryNested(`process.Ext.code_signature`, [ - createEntryMatch('trusted', 'true'), - createEntryMatch('subject_name', conditionEntry.value), + createEntryMatch('trusted', OperatorEntryField.included, 'true'), + createEntryMatch('subject_name', OperatorEntryField.included, conditionEntry.value), ]); + } else if ( + conditionEntry.field === ConditionEntryField.PATH && + conditionEntry.operator === OperatorEntryField.wildcard_caseless + ) { + return createEntryMatch( + `process.executable.caseless`, + OperatorEntryField.wildcard_caseless, + conditionEntry.value + ); } else { - return createEntryMatch(`process.executable.caseless`, conditionEntry.value); + return createEntryMatch( + `process.executable.caseless`, + OperatorEntryField.included, + conditionEntry.value + ); } }); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/filters/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/filters/types.ts index e1618d217d0dc..48968e8cb964d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/filters/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/filters/types.ts @@ -44,6 +44,6 @@ export interface CreateFieldAndSetTuplesOptions { export interface FieldSet { field: string; - operator: 'excluded' | 'included'; + operator: 'excluded' | 'included' | 'wildcard_caseless'; matchedSet: Set; } From c0470256514dcdc9b03b52ae0eeb70921e744ea6 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Thu, 22 Apr 2021 20:27:53 +0200 Subject: [PATCH 11/36] update tests refs 2ac56ee839342c520928487b4a49f25938fa08ca refs elastic/security-team/issues/543 --- .../common/schemas/common/schemas.test.ts | 9 + .../routes/trusted_apps/handlers.test.ts | 25 ++- .../routes/trusted_apps/mapping.test.ts | 189 +++++++++++++++--- .../routes/trusted_apps/service.test.ts | 56 +++++- 4 files changed, 240 insertions(+), 39 deletions(-) diff --git a/x-pack/plugins/lists/common/schemas/common/schemas.test.ts b/x-pack/plugins/lists/common/schemas/common/schemas.test.ts index 9f3abb9259f6c..69cf794b5575d 100644 --- a/x-pack/plugins/lists/common/schemas/common/schemas.test.ts +++ b/x-pack/plugins/lists/common/schemas/common/schemas.test.ts @@ -53,6 +53,15 @@ describe('Common schemas', () => { expect(message.schema).toEqual(payload); }); + test('it should validate for "wildcard_caseless"', () => { + const payload = 'wildcard_caseless'; + const decoded = operator.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + test('it should contain same amount of keys as enum', () => { // Might seem like a weird test, but its meant to // ensure that if operator is updated, you diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.test.ts index 42a2e0f43d970..700f676495ec6 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.test.ts @@ -18,6 +18,7 @@ import { ConditionEntryField, NewTrustedApp, OperatingSystem, + OperatorEntryField, TrustedApp, } from '../../../../common/endpoint/types'; import { parseExperimentalConfigValue } from '../../../../common/experimental_features'; @@ -44,8 +45,12 @@ const EXCEPTION_LIST_ITEM: ExceptionListItemSchema = { created_by: 'admin', description: 'Linux trusted app 1', entries: [ - createEntryMatch('process.executable.caseless', '/bin/malware'), - createEntryMatch('process.hash.md5', '1234234659af249ddf3e40864e9fb241'), + createEntryMatch('process.executable.caseless', OperatorEntryField.included, '/bin/malware'), + createEntryMatch( + 'process.hash.md5', + OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' + ), ], item_id: '123', list_id: 'endpoint_trusted_apps', @@ -66,8 +71,12 @@ const NEW_TRUSTED_APP: NewTrustedApp = { os: OperatingSystem.LINUX, effectScope: { type: 'global' }, entries: [ - createConditionEntry(ConditionEntryField.PATH, '/bin/malware'), - createConditionEntry(ConditionEntryField.HASH, '1234234659af249ddf3e40864e9fb241'), + createConditionEntry(ConditionEntryField.PATH, OperatorEntryField.included, '/bin/malware'), + createConditionEntry( + ConditionEntryField.HASH, + OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' + ), ], }; @@ -83,8 +92,12 @@ const TRUSTED_APP: TrustedApp = { os: OperatingSystem.LINUX, effectScope: { type: 'global' }, entries: [ - createConditionEntry(ConditionEntryField.HASH, '1234234659af249ddf3e40864e9fb241'), - createConditionEntry(ConditionEntryField.PATH, '/bin/malware'), + createConditionEntry( + ConditionEntryField.HASH, + OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' + ), + createConditionEntry(ConditionEntryField.PATH, OperatorEntryField.included, '/bin/malware'), ], }; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts index 68ff7d03e413a..689a83f06e281 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts @@ -12,6 +12,7 @@ import { ConditionEntryField, NewTrustedApp, OperatingSystem, + OperatorEntryField, TrustedApp, UpdateTrustedApp, } from '../../../../common/endpoint/types'; @@ -79,13 +80,25 @@ describe('mapping', () => { description: 'Linux Trusted App', effectScope: { type: 'global' }, os: OperatingSystem.LINUX, - entries: [createConditionEntry(ConditionEntryField.PATH, '/bin/malware')], + entries: [ + createConditionEntry( + ConditionEntryField.PATH, + OperatorEntryField.included, + '/bin/malware' + ), + ], }, createExceptionListItemOptions({ name: 'linux trusted app', description: 'Linux Trusted App', osTypes: ['linux'], - entries: [createEntryMatch('process.executable.caseless', '/bin/malware')], + entries: [ + createEntryMatch( + 'process.executable.caseless', + OperatorEntryField.included, + '/bin/malware' + ), + ], }) ); }); @@ -97,13 +110,25 @@ describe('mapping', () => { description: 'MacOS Trusted App', effectScope: { type: 'global' }, os: OperatingSystem.MAC, - entries: [createConditionEntry(ConditionEntryField.PATH, '/bin/malware')], + entries: [ + createConditionEntry( + ConditionEntryField.PATH, + OperatorEntryField.included, + '/bin/malware' + ), + ], }, createExceptionListItemOptions({ name: 'macos trusted app', description: 'MacOS Trusted App', osTypes: ['macos'], - entries: [createEntryMatch('process.executable.caseless', '/bin/malware')], + entries: [ + createEntryMatch( + 'process.executable.caseless', + OperatorEntryField.included, + '/bin/malware' + ), + ], }) ); }); @@ -115,13 +140,25 @@ describe('mapping', () => { description: 'Windows Trusted App', effectScope: { type: 'global' }, os: OperatingSystem.WINDOWS, - entries: [createConditionEntry(ConditionEntryField.PATH, 'C:\\Program Files\\Malware')], + entries: [ + createConditionEntry( + ConditionEntryField.PATH, + OperatorEntryField.included, + 'C:\\Program Files\\Malware' + ), + ], }, createExceptionListItemOptions({ name: 'windows trusted app', description: 'Windows Trusted App', osTypes: ['windows'], - entries: [createEntryMatch('process.executable.caseless', 'C:\\Program Files\\Malware')], + entries: [ + createEntryMatch( + 'process.executable.caseless', + OperatorEntryField.included, + 'C:\\Program Files\\Malware' + ), + ], }) ); }); @@ -133,7 +170,13 @@ describe('mapping', () => { description: 'Signed Trusted App', effectScope: { type: 'global' }, os: OperatingSystem.WINDOWS, - entries: [createConditionEntry(ConditionEntryField.SIGNER, 'Microsoft Windows')], + entries: [ + createConditionEntry( + ConditionEntryField.SIGNER, + OperatorEntryField.included, + 'Microsoft Windows' + ), + ], }, createExceptionListItemOptions({ name: 'Signed trusted app', @@ -141,8 +184,8 @@ describe('mapping', () => { osTypes: ['windows'], entries: [ createEntryNested('process.Ext.code_signature', [ - createEntryMatch('trusted', 'true'), - createEntryMatch('subject_name', 'Microsoft Windows'), + createEntryMatch('trusted', OperatorEntryField.included, 'true'), + createEntryMatch('subject_name', OperatorEntryField.included, 'Microsoft Windows'), ]), ], }) @@ -157,14 +200,24 @@ describe('mapping', () => { effectScope: { type: 'global' }, os: OperatingSystem.LINUX, entries: [ - createConditionEntry(ConditionEntryField.HASH, '1234234659af249ddf3e40864e9fb241'), + createConditionEntry( + ConditionEntryField.HASH, + OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' + ), ], }, createExceptionListItemOptions({ name: 'MD5 trusted app', description: 'MD5 Trusted App', osTypes: ['linux'], - entries: [createEntryMatch('process.hash.md5', '1234234659af249ddf3e40864e9fb241')], + entries: [ + createEntryMatch( + 'process.hash.md5', + OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' + ), + ], }) ); }); @@ -179,6 +232,7 @@ describe('mapping', () => { entries: [ createConditionEntry( ConditionEntryField.HASH, + OperatorEntryField.included, 'f635da961234234659af249ddf3e40864e9fb241' ), ], @@ -188,7 +242,11 @@ describe('mapping', () => { description: 'SHA1 Trusted App', osTypes: ['linux'], entries: [ - createEntryMatch('process.hash.sha1', 'f635da961234234659af249ddf3e40864e9fb241'), + createEntryMatch( + 'process.hash.sha1', + OperatorEntryField.included, + 'f635da961234234659af249ddf3e40864e9fb241' + ), ], }) ); @@ -204,6 +262,7 @@ describe('mapping', () => { entries: [ createConditionEntry( ConditionEntryField.HASH, + OperatorEntryField.included, 'f635da96124659af249ddf3e40864e9fb234234659af249ddf3e40864e9fb241' ), ], @@ -215,6 +274,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.hash.sha256', + OperatorEntryField.included, 'f635da96124659af249ddf3e40864e9fb234234659af249ddf3e40864e9fb241' ), ], @@ -230,14 +290,24 @@ describe('mapping', () => { effectScope: { type: 'global' }, os: OperatingSystem.LINUX, entries: [ - createConditionEntry(ConditionEntryField.HASH, '1234234659Af249ddf3e40864E9FB241'), + createConditionEntry( + ConditionEntryField.HASH, + OperatorEntryField.included, + '1234234659Af249ddf3e40864E9FB241' + ), ], }, createExceptionListItemOptions({ name: 'MD5 trusted app', description: 'MD5 Trusted App', osTypes: ['linux'], - entries: [createEntryMatch('process.hash.md5', '1234234659af249ddf3e40864e9fb241')], + entries: [ + createEntryMatch( + 'process.hash.md5', + OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' + ), + ], }) ); }); @@ -257,7 +327,13 @@ describe('mapping', () => { created_at: '11/11/2011T11:11:11.111', created_by: 'admin', os_types: ['linux'], - entries: [createEntryMatch('process.executable.caseless', '/bin/malware')], + entries: [ + createEntryMatch( + 'process.executable.caseless', + OperatorEntryField.included, + '/bin/malware' + ), + ], }), { id: '123', @@ -270,7 +346,13 @@ describe('mapping', () => { updated_at: '11/11/2011T11:11:11.111', updated_by: 'admin', os: OperatingSystem.LINUX, - entries: [createConditionEntry(ConditionEntryField.PATH, '/bin/malware')], + entries: [ + createConditionEntry( + ConditionEntryField.PATH, + OperatorEntryField.included, + '/bin/malware' + ), + ], } ); }); @@ -284,7 +366,13 @@ describe('mapping', () => { created_at: '11/11/2011T11:11:11.111', created_by: 'admin', os_types: ['macos'], - entries: [createEntryMatch('process.executable.caseless', '/bin/malware')], + entries: [ + createEntryMatch( + 'process.executable.caseless', + OperatorEntryField.included, + '/bin/malware' + ), + ], }), { id: '123', @@ -297,7 +385,13 @@ describe('mapping', () => { updated_at: '11/11/2011T11:11:11.111', updated_by: 'admin', os: OperatingSystem.MAC, - entries: [createConditionEntry(ConditionEntryField.PATH, '/bin/malware')], + entries: [ + createConditionEntry( + ConditionEntryField.PATH, + OperatorEntryField.included, + '/bin/malware' + ), + ], } ); }); @@ -311,7 +405,13 @@ describe('mapping', () => { created_at: '11/11/2011T11:11:11.111', created_by: 'admin', os_types: ['windows'], - entries: [createEntryMatch('process.executable.caseless', 'C:\\Program Files\\Malware')], + entries: [ + createEntryMatch( + 'process.executable.caseless', + OperatorEntryField.included, + 'C:\\Program Files\\Malware' + ), + ], }), { id: '123', @@ -324,7 +424,13 @@ describe('mapping', () => { updated_at: '11/11/2011T11:11:11.111', updated_by: 'admin', os: OperatingSystem.WINDOWS, - entries: [createConditionEntry(ConditionEntryField.PATH, 'C:\\Program Files\\Malware')], + entries: [ + createConditionEntry( + ConditionEntryField.PATH, + OperatorEntryField.included, + 'C:\\Program Files\\Malware' + ), + ], } ); }); @@ -340,8 +446,8 @@ describe('mapping', () => { os_types: ['windows'], entries: [ createEntryNested('process.Ext.code_signature', [ - createEntryMatch('trusted', 'true'), - createEntryMatch('subject_name', 'Microsoft Windows'), + createEntryMatch('trusted', OperatorEntryField.included, 'true'), + createEntryMatch('subject_name', OperatorEntryField.included, 'Microsoft Windows'), ]), ], }), @@ -356,7 +462,13 @@ describe('mapping', () => { updated_at: '11/11/2011T11:11:11.111', updated_by: 'admin', os: OperatingSystem.WINDOWS, - entries: [createConditionEntry(ConditionEntryField.SIGNER, 'Microsoft Windows')], + entries: [ + createConditionEntry( + ConditionEntryField.SIGNER, + OperatorEntryField.included, + 'Microsoft Windows' + ), + ], } ); }); @@ -370,7 +482,13 @@ describe('mapping', () => { created_at: '11/11/2011T11:11:11.111', created_by: 'admin', os_types: ['linux'], - entries: [createEntryMatch('process.hash.md5', '1234234659af249ddf3e40864e9fb241')], + entries: [ + createEntryMatch( + 'process.hash.md5', + OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' + ), + ], }), { id: '123', @@ -384,7 +502,11 @@ describe('mapping', () => { updated_by: 'admin', os: OperatingSystem.LINUX, entries: [ - createConditionEntry(ConditionEntryField.HASH, '1234234659af249ddf3e40864e9fb241'), + createConditionEntry( + ConditionEntryField.HASH, + OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' + ), ], } ); @@ -400,7 +522,11 @@ describe('mapping', () => { created_by: 'admin', os_types: ['linux'], entries: [ - createEntryMatch('process.hash.sha1', 'f635da961234234659af249ddf3e40864e9fb241'), + createEntryMatch( + 'process.hash.sha1', + OperatorEntryField.included, + 'f635da961234234659af249ddf3e40864e9fb241' + ), ], }), { @@ -417,6 +543,7 @@ describe('mapping', () => { entries: [ createConditionEntry( ConditionEntryField.HASH, + OperatorEntryField.included, 'f635da961234234659af249ddf3e40864e9fb241' ), ], @@ -436,6 +563,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.hash.sha256', + OperatorEntryField.included, 'f635da96124659af249ddf3e40864e9fb234234659af249ddf3e40864e9fb241' ), ], @@ -454,6 +582,7 @@ describe('mapping', () => { entries: [ createConditionEntry( ConditionEntryField.HASH, + OperatorEntryField.included, 'f635da96124659af249ddf3e40864e9fb234234659af249ddf3e40864e9fb241' ), ], @@ -469,7 +598,13 @@ describe('mapping', () => { description: 'Linux Trusted App', effectScope: { type: 'global' }, os: OperatingSystem.LINUX, - entries: [createConditionEntry(ConditionEntryField.PATH, '/bin/malware')], + entries: [ + createConditionEntry( + ConditionEntryField.PATH, + OperatorEntryField.included, + '/bin/malware' + ), + ], version: 'abc', }; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.test.ts index 42f4c6d157389..1f4048d1fedc1 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.test.ts @@ -11,6 +11,7 @@ import { ExceptionListClient } from '../../../../../lists/server'; import { ConditionEntryField, OperatingSystem, + OperatorEntryField, TrustedApp, } from '../../../../common/endpoint/types'; import { createConditionEntry, createEntryMatch } from './mapping'; @@ -37,8 +38,12 @@ const EXCEPTION_LIST_ITEM: ExceptionListItemSchema = { created_by: 'admin', description: 'Linux trusted app 1', entries: [ - createEntryMatch('process.executable.caseless', '/bin/malware'), - createEntryMatch('process.hash.md5', '1234234659af249ddf3e40864e9fb241'), + createEntryMatch('process.executable.caseless', OperatorEntryField.included, '/bin/malware'), + createEntryMatch( + 'process.hash.md5', + OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' + ), ], item_id: '123', list_id: 'endpoint_trusted_apps', @@ -65,8 +70,12 @@ const TRUSTED_APP: TrustedApp = { os: OperatingSystem.LINUX, effectScope: { type: 'global' }, entries: [ - createConditionEntry(ConditionEntryField.HASH, '1234234659af249ddf3e40864e9fb241'), - createConditionEntry(ConditionEntryField.PATH, '/bin/malware'), + createConditionEntry( + ConditionEntryField.HASH, + OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' + ), + createConditionEntry(ConditionEntryField.PATH, OperatorEntryField.included, '/bin/malware'), ], }; @@ -109,8 +118,43 @@ describe('service', () => { effectScope: { type: 'global' }, os: OperatingSystem.LINUX, entries: [ - createConditionEntry(ConditionEntryField.PATH, '/bin/malware'), - createConditionEntry(ConditionEntryField.HASH, '1234234659af249ddf3e40864e9fb241'), + createConditionEntry( + ConditionEntryField.PATH, + OperatorEntryField.included, + '/bin/malware' + ), + createConditionEntry( + ConditionEntryField.HASH, + OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' + ), + ], + }); + + expect(result).toEqual({ data: TRUSTED_APP }); + + expect(exceptionsListClient.createTrustedAppsList).toHaveBeenCalled(); + }); + + it('should create trusted app with correct wildcard_caseless operator', async () => { + exceptionsListClient.createExceptionListItem.mockResolvedValue(EXCEPTION_LIST_ITEM); + + const result = await createTrustedApp(exceptionsListClient, { + name: 'linux trusted app 1', + description: 'Linux trusted app 1', + effectScope: { type: 'global' }, + os: OperatingSystem.LINUX, + entries: [ + createConditionEntry( + ConditionEntryField.PATH, + OperatorEntryField.wildcard_caseless, + '/bin/malware' + ), + createConditionEntry( + ConditionEntryField.HASH, + OperatorEntryField.wildcard_caseless, + '1234234659af249ddf3e40864e9fb241' + ), ], }); From 74d5193b2d9259ae681242aa24efc2e6650e5638 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Thu, 22 Apr 2021 20:45:39 +0200 Subject: [PATCH 12/36] remove redundant code review changes --- .../components/condition_entry_input/index.tsx | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index dd843df3a4858..04b1cc5836552 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -174,29 +174,25 @@ export const ConditionEntryInput = memo( /> - {entry.field === ConditionEntryField.PATH ? ( - - + + + {entry.field === ConditionEntryField.PATH ? ( - - - ) : ( - - + ) : ( - - - )} + )} + + Date: Fri, 23 Apr 2021 10:07:54 +0200 Subject: [PATCH 13/36] better type assertion review changes --- .../view/components/condition_entry_input/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index 04b1cc5836552..56a1e67e134de 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -126,7 +126,7 @@ export const ConditionEntryInput = memo( // use a memoized callback to // limit list iteration for re-renders const operatorOptions = useMemo>>(() => { - return (Object.keys(OperatorEntryField) as [ConditionEntry['operator']]).map((value) => ({ + return (Object.keys(OperatorEntryField) as OperatorEntryField[]).map((value) => ({ dropdownDisplay: OPERATOR_TITLES[value], inputDisplay: OPERATOR_TITLES[value], value, From f6cd3a8abe664bbc3148d96d6f2c27373875e941 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Fri, 23 Apr 2021 10:19:30 +0200 Subject: [PATCH 14/36] move operator options out of component - these do not depend on component props and thus no need to have it within a useMemo callback. - review changes --- .../components/condition_entry_input/index.tsx | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index 56a1e67e134de..7149061ab95e9 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -75,6 +75,12 @@ const StyledEuiFlexGroup = styled(EuiFlexGroup)` grid-template-areas: 'field operator value remove'; `; +const operatorOptions = (Object.keys(OperatorEntryField) as OperatorEntryField[]).map((value) => ({ + dropdownDisplay: OPERATOR_TITLES[value], + inputDisplay: OPERATOR_TITLES[value], + value, +})); + export const ConditionEntryInput = memo( ({ os, @@ -123,16 +129,6 @@ export const ConditionEntryInput = memo( ]; }, [os]); - // use a memoized callback to - // limit list iteration for re-renders - const operatorOptions = useMemo>>(() => { - return (Object.keys(OperatorEntryField) as OperatorEntryField[]).map((value) => ({ - dropdownDisplay: OPERATOR_TITLES[value], - inputDisplay: OPERATOR_TITLES[value], - value, - })); - }, []); - const handleValueUpdate = useCallback>( (ev) => onChange({ ...entry, value: ev.target.value }, entry), [entry, onChange] From a6725b94e8b0854d03214777862502d936bfa3da Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Fri, 23 Apr 2021 10:30:39 +0200 Subject: [PATCH 15/36] derive keys from operator entry field review changes --- .../pages/trusted_apps/view/translations.ts | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) 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 ef86e8f084a74..7071022fb893f 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 @@ -10,8 +10,8 @@ import { TrustedApp, MacosLinuxConditionEntry, WindowsConditionEntry, - ConditionEntry, ConditionEntryField, + OperatorEntryField, } from '../../../../../common/endpoint/types'; export { OS_TITLES } from '../../../common/translations'; @@ -52,13 +52,19 @@ export const CONDITION_FIELD_DESCRIPTION: { [K in ConditionEntryField]: string } ), }; -export const OPERATOR_TITLES: { [K in ConditionEntry['operator']]: string } = { - included: i18n.translate('xpack.securitySolution.trustedapps.card.operator.is', { - defaultMessage: 'is', - }), - wildcard_caseless: i18n.translate('xpack.securitySolution.trustedapps.card.operator.matches', { - defaultMessage: 'matches', - }), +export const OPERATOR_TITLES: { [K in OperatorEntryField]: string } = { + [OperatorEntryField.included]: i18n.translate( + 'xpack.securitySolution.trustedapps.card.operator.is', + { + defaultMessage: 'is', + } + ), + [OperatorEntryField.wildcard_caseless]: i18n.translate( + 'xpack.securitySolution.trustedapps.card.operator.matches', + { + defaultMessage: 'matches', + } + ), }; export const PROPERTY_TITLES: Readonly< From 4def2890229604c6fc3ad8f9b2bb53a0989ab14a Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Fri, 23 Apr 2021 12:53:51 +0200 Subject: [PATCH 16/36] update type --- .../server/endpoint/routes/trusted_apps/mapping.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts index 22d87e888f05c..4ed40e9765341 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts @@ -195,7 +195,7 @@ const hashType = (hash: string): 'md5' | 'sha256' | 'sha1' | undefined => { export const createEntryMatch = ( field: string, - operator: ConditionEntry['operator'], + operator: OperatorEntryField, value: string ): EntryMatch => { return { field, value, type: 'match', operator }; From 0a60598cbaaa6d3c9658f4977d64a87fac5cc946 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Fri, 23 Apr 2021 13:26:40 +0200 Subject: [PATCH 17/36] use custom styles for aligning input fields review changes --- .../condition_entry_input/index.tsx | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index 7149061ab95e9..21a472d80a955 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -11,8 +11,6 @@ import { i18n } from '@kbn/i18n'; import { EuiButtonIcon, EuiFieldText, - EuiFlexGroup, - EuiFlexItem, EuiFormRow, EuiSuperSelect, EuiSuperSelectOption, @@ -69,12 +67,18 @@ export interface ConditionEntryInputProps { // adding a style prop on EuiFlexGroup works only partially // and for some odd reason garbles up gridTemplateAreas entry -const StyledEuiFlexGroup = styled(EuiFlexGroup)` +const InputGroup = styled.div` display: grid; grid-template-columns: 25% 25% 45% 5%; grid-template-areas: 'field operator value remove'; `; +const InputItem = styled.div` + align-self: center; + margin: 4px; + vertical-align: baseline; +`; + const operatorOptions = (Object.keys(OperatorEntryField) as OperatorEntryField[]).map((value) => ({ dropdownDisplay: OPERATOR_TITLES[value], inputDisplay: OPERATOR_TITLES[value], @@ -153,14 +157,8 @@ export const ConditionEntryInput = memo( }, [entry, onVisited]); return ( - - + + ( data-test-subj={getTestId('field')} /> - - + + {entry.field === ConditionEntryField.PATH ? ( ( /> )} - - + + ( data-test-subj={getTestId('value')} /> - - + + {/* Unicode `nbsp` is used below so that Remove button is property displayed */} ( data-test-subj={getTestId('remove')} /> - - + + ); } ); From c3643f0c940ede0e3306f5f1bf04297afa873ae3 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Fri, 23 Apr 2021 16:19:12 +0200 Subject: [PATCH 18/36] add a custom type for trusted_apps operator undo changes from list plugin and server/lib/detection_engine refs 2ac56ee839342c520928487b4a49f25938fa08ca refs elastic/security-team/issues/543 --- x-pack/plugins/lists/common/schemas/common/schemas.ts | 3 +-- .../server/endpoint/routes/trusted_apps/mapping.ts | 9 ++++++++- .../server/lib/detection_engine/signals/filters/types.ts | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/lists/common/schemas/common/schemas.ts b/x-pack/plugins/lists/common/schemas/common/schemas.ts index d702ef157ca43..f261e4e3eefa6 100644 --- a/x-pack/plugins/lists/common/schemas/common/schemas.ts +++ b/x-pack/plugins/lists/common/schemas/common/schemas.ts @@ -276,12 +276,11 @@ export type CursorOrUndefined = t.TypeOf; export const namespace_type = DefaultNamespace; export const operatorIncluded = t.keyof({ included: null }); -export const operator = t.keyof({ excluded: null, included: null, wildcard_caseless: null }); +export const operator = t.keyof({ excluded: null, included: null }); export type Operator = t.TypeOf; export enum OperatorEnum { INCLUDED = 'included', EXCLUDED = 'excluded', - WILDCARD_CASELESS = 'wildcard_caseless', } export enum OperatorTypeEnum { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts index 4ed40e9765341..cae1d9c27eb7f 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts @@ -14,6 +14,7 @@ import { EntryNested, ExceptionListItemSchema, NestedEntriesArray, + Operator, } from '../../../../../lists/common'; import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/constants'; import { @@ -75,7 +76,13 @@ export const tagsToEffectScope = (tags: string[]): EffectScope => { } }; -export const entriesToConditionEntriesMap = (entries: EntriesArray): ConditionEntriesMap => { +type TrustedAppsEntriesArray = Omit & { + operator: Operator | 'wildcard_caseless'; +}; + +export const entriesToConditionEntriesMap = ( + entries: TrustedAppsEntriesArray +): ConditionEntriesMap => { return entries.reduce((result, entry) => { if (entry.field.startsWith('process.hash') && entry.type === 'match') { return { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/filters/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/filters/types.ts index 48968e8cb964d..e1618d217d0dc 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/filters/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/filters/types.ts @@ -44,6 +44,6 @@ export interface CreateFieldAndSetTuplesOptions { export interface FieldSet { field: string; - operator: 'excluded' | 'included' | 'wildcard_caseless'; + operator: 'excluded' | 'included'; matchedSet: Set; } From f9cb7eddda64e8198470cfb9f19a099c19e19dae Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Mon, 26 Apr 2021 17:43:58 +0200 Subject: [PATCH 19/36] add wildcard entry type refs elastic/security-team/issues/543 refs https://github.com/elastic/kibana/pull/97623#pullrequestreview-642618462 --- .../lists/common/schemas/common/schemas.ts | 1 + .../lists/common/schemas/types/entries.ts | 19 +++++++++++++++-- .../types/entry_match_wildcard_caseless.ts | 21 +++++++++++++++++++ .../lists/common/schemas/types/index.ts | 1 + x-pack/plugins/lists/common/shared_exports.ts | 2 ++ .../exceptions/components/builder/types.ts | 5 ++++- 6 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 x-pack/plugins/lists/common/schemas/types/entry_match_wildcard_caseless.ts diff --git a/x-pack/plugins/lists/common/schemas/common/schemas.ts b/x-pack/plugins/lists/common/schemas/common/schemas.ts index f261e4e3eefa6..7e43e7dd5f4ab 100644 --- a/x-pack/plugins/lists/common/schemas/common/schemas.ts +++ b/x-pack/plugins/lists/common/schemas/common/schemas.ts @@ -287,6 +287,7 @@ export enum OperatorTypeEnum { NESTED = 'nested', MATCH = 'match', MATCH_ANY = 'match_any', + WILDCARD = 'wildcard', EXISTS = 'exists', LIST = 'list', } diff --git a/x-pack/plugins/lists/common/schemas/types/entries.ts b/x-pack/plugins/lists/common/schemas/types/entries.ts index 277751bf1c271..0ec7474a336b6 100644 --- a/x-pack/plugins/lists/common/schemas/types/entries.ts +++ b/x-pack/plugins/lists/common/schemas/types/entries.ts @@ -12,12 +12,27 @@ import { entriesMatch } from './entry_match'; import { entriesExists } from './entry_exists'; import { entriesList } from './entry_list'; import { entriesNested } from './entry_nested'; +import { entriesMatchWildcardCaseless } from './entry_match_wildcard_caseless'; -export const entry = t.union([entriesMatch, entriesMatchAny, entriesList, entriesExists]); +export const entry = t.union([ + entriesMatch, + entriesMatchAny, + entriesList, + entriesExists, + entriesNested, + entriesMatchWildcardCaseless, +]); export type Entry = t.TypeOf; export const entriesArray = t.array( - t.union([entriesMatch, entriesMatchAny, entriesList, entriesExists, entriesNested]) + t.union([ + entriesMatch, + entriesMatchAny, + entriesList, + entriesExists, + entriesNested, + entriesMatchWildcardCaseless, + ]) ); export type EntriesArray = t.TypeOf; diff --git a/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard_caseless.ts b/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard_caseless.ts new file mode 100644 index 0000000000000..f36ebdd8ac8ca --- /dev/null +++ b/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard_caseless.ts @@ -0,0 +1,21 @@ +/* + * 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 * as t from 'io-ts'; + +import { NonEmptyString } from '../../shared_imports'; +import { operator } from '../common/schemas'; + +export const entriesMatchWildcardCaseless = t.exact( + t.type({ + field: NonEmptyString, + operator, + type: t.keyof({ wildcard: null }), + value: NonEmptyString, + }) +); +export type EntriesMatchWildcardCaseless = t.TypeOf; diff --git a/x-pack/plugins/lists/common/schemas/types/index.ts b/x-pack/plugins/lists/common/schemas/types/index.ts index 98342f3b9c153..01020752b2597 100644 --- a/x-pack/plugins/lists/common/schemas/types/index.ts +++ b/x-pack/plugins/lists/common/schemas/types/index.ts @@ -15,6 +15,7 @@ export * from './default_namespace'; export * from './entries'; export * from './entry_match'; export * from './entry_match_any'; +export * from './entry_match_wildcard_caseless'; export * from './entry_list'; export * from './entry_exists'; export * from './entry_nested'; diff --git a/x-pack/plugins/lists/common/shared_exports.ts b/x-pack/plugins/lists/common/shared_exports.ts index 23da48b35a9d4..8fcf611ccd7e1 100644 --- a/x-pack/plugins/lists/common/shared_exports.ts +++ b/x-pack/plugins/lists/common/shared_exports.ts @@ -20,6 +20,7 @@ export { EntryExists, EntryMatch, EntryMatchAny, + EntriesMatchWildcardCaseless, EntryNested, EntryList, EntriesArray, @@ -39,6 +40,7 @@ export { nestedEntryItem, entriesMatch, entriesMatchAny, + entriesMatchWildcardCaseless, entriesExists, entriesList, namespaceType, diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/types.ts b/x-pack/plugins/lists/public/exceptions/components/builder/types.ts index cdb4f735aa103..5ac72b3ef546f 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/types.ts +++ b/x-pack/plugins/lists/public/exceptions/components/builder/types.ts @@ -9,6 +9,7 @@ import { IFieldType } from '../../../../../../../src/plugins/data/common'; import { OperatorOption } from '../autocomplete/types'; import { CreateExceptionListItemSchema, + EntriesMatchWildcardCaseless, Entry, EntryExists, EntryMatch, @@ -34,7 +35,7 @@ export interface EmptyEntry { id: string; field: string | undefined; operator: OperatorEnum; - type: OperatorTypeEnum.MATCH | OperatorTypeEnum.MATCH_ANY; + type: OperatorTypeEnum.MATCH | OperatorTypeEnum.MATCH_ANY | OperatorTypeEnum.WILDCARD; value: string | string[] | undefined; } @@ -53,6 +54,7 @@ export interface EmptyNestedEntry { entries: Array< | (EntryMatch & { id?: string }) | (EntryMatchAny & { id?: string }) + | (EntriesMatchWildcardCaseless & { id?: string }) | (EntryExists & { id?: string }) >; } @@ -69,6 +71,7 @@ export type BuilderEntryNested = Omit & { entries: Array< | (EntryMatch & { id?: string }) | (EntryMatchAny & { id?: string }) + | (EntriesMatchWildcardCaseless & { id?: string }) | (EntryExists & { id?: string }) >; }; From b3f5dc45539da80e66f5ae8240737717f2a14766 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Mon, 26 Apr 2021 17:47:19 +0200 Subject: [PATCH 20/36] use the new entry type refs elastic/security-team/issues/543 refs https://github.com/elastic/kibana/pull/97623#pullrequestreview-642618462 --- .../common/endpoint/schema/trusted_apps.ts | 14 ++-- .../common/endpoint/types/trusted_apps.ts | 13 ++-- .../common/shared_imports.ts | 2 + .../common/components/exceptions/types.ts | 3 + .../condition_entry_input/index.tsx | 12 ++-- .../components/trusted_app_card/index.tsx | 6 +- .../pages/trusted_apps/view/translations.ts | 22 +++--- .../endpoint/routes/trusted_apps/mapping.ts | 71 ++++++------------- 8 files changed, 58 insertions(+), 85 deletions(-) diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts index 03cbe53f60320..9858f2a72c2d0 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { ConditionEntry, ConditionEntryField, OperatingSystem, OperatorEntryField } from '../types'; +import { ConditionEntry, ConditionEntryField, OperatingSystem } from '../types'; import { getDuplicateFields, isValidHash } from '../service/trusted_apps/validations'; export const DeleteTrustedAppsRequestSchema = { @@ -29,17 +29,13 @@ export const GetTrustedAppsRequestSchema = { }), }; -const ConditionEntryTypeSchema = schema.literal('match'); -// when field === PATH -> operator in ('included', 'wildcard_caseless') else operator === 'included' -const ConditionEntryOperatorSchema = schema.conditional( +const ConditionEntryTypeSchema = schema.conditional( schema.siblingRef('field'), ConditionEntryField.PATH, - schema.oneOf([ - schema.literal(OperatorEntryField.included), - schema.literal(OperatorEntryField.wildcard_caseless), - ]), - schema.literal(OperatorEntryField.included) + schema.oneOf([schema.literal('match'), schema.literal('wildcard')]), + schema.literal('match') ); +const ConditionEntryOperatorSchema = schema.literal('included' as ConditionEntry['operator']); /* * A generic Entry schema to be used for a specific entry schema depending on the OS diff --git a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts index 371f7848b6bb4..3c854dbb7bd72 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts @@ -7,6 +7,8 @@ import { TypeOf } from '@kbn/config-schema'; import { ApplicationStart } from 'kibana/public'; + +import { Entry } from '../../../../lists/common/schemas/types/entries'; import { DeleteTrustedAppsRequestSchema, GetOneTrustedAppRequestSchema, @@ -69,14 +71,15 @@ export enum ConditionEntryField { SIGNER = 'process.Ext.code_signature', } -export enum OperatorEntryField { - included = 'included', - wildcard_caseless = 'wildcard_caseless', +export enum OperatorFieldIds { + is = 'is', + matches = 'matches', } + export interface ConditionEntry { field: T; - type: 'match'; - operator: keyof typeof OperatorEntryField; + type: Entry['type']; + operator: 'included'; value: string; } diff --git a/x-pack/plugins/security_solution/common/shared_imports.ts b/x-pack/plugins/security_solution/common/shared_imports.ts index aaae0d4dc25ef..f02cc472e9f60 100644 --- a/x-pack/plugins/security_solution/common/shared_imports.ts +++ b/x-pack/plugins/security_solution/common/shared_imports.ts @@ -20,6 +20,7 @@ export { EntryExists, EntryMatch, EntryMatchAny, + EntriesMatchWildcardCaseless, EntryNested, EntryList, EntriesArray, @@ -38,6 +39,7 @@ export { nestedEntryItem, entriesMatch, entriesMatchAny, + entriesMatchWildcardCaseless, entriesExists, entriesList, namespaceType, diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/types.ts b/x-pack/plugins/security_solution/public/common/components/exceptions/types.ts index c7a125daa54f8..7bce9f0b557b2 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/types.ts +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/types.ts @@ -15,6 +15,7 @@ import { Entry, EntryMatch, EntryMatchAny, + EntriesMatchWildcardCaseless, EntryExists, ExceptionListItemSchema, CreateExceptionListItemSchema, @@ -92,6 +93,7 @@ export interface EmptyNestedEntry { type: OperatorTypeEnum.NESTED; entries: Array< | (EntryMatch & { id?: string }) + | (EntriesMatchWildcardCaseless & { id?: string }) | (EntryMatchAny & { id?: string }) | (EntryExists & { id?: string }) >; @@ -108,6 +110,7 @@ export type BuilderEntryNested = Omit & { id?: string; entries: Array< | (EntryMatch & { id?: string }) + | (EntriesMatchWildcardCaseless & { id?: string }) | (EntryMatchAny & { id?: string }) | (EntryExists & { id?: string }) >; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index 21a472d80a955..1f3fed2fd4b61 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -20,7 +20,7 @@ import { import { ConditionEntry, ConditionEntryField, - OperatorEntryField, + OperatorFieldIds, OperatingSystem, } from '../../../../../../../common/endpoint/types'; @@ -79,10 +79,10 @@ const InputItem = styled.div` vertical-align: baseline; `; -const operatorOptions = (Object.keys(OperatorEntryField) as OperatorEntryField[]).map((value) => ({ +const operatorOptions = (Object.keys(OperatorFieldIds) as OperatorFieldIds[]).map((value) => ({ dropdownDisplay: OPERATOR_TITLES[value], inputDisplay: OPERATOR_TITLES[value], - value, + value: value === 'matches' ? 'wildcard' : 'match', })); export const ConditionEntryInput = memo( @@ -144,7 +144,7 @@ export const ConditionEntryInput = memo( ); const handleOperatorUpdate = useCallback( - (newOperator) => onChange({ ...entry, operator: newOperator }, entry), + (newOperator) => onChange({ ...entry, type: newOperator }, entry), [entry, onChange] ); @@ -174,13 +174,13 @@ export const ConditionEntryInput = memo( ) : ( diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_app_card/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_app_card/index.tsx index aadee204dab14..8289792b81f89 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_app_card/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_app_card/index.tsx @@ -45,7 +45,7 @@ const getEntriesColumnDefinitions = (): Array truncateText: true, textOnly: true, width: '30%', - render(field: Entry['field'], entry: Entry) { + render(field: Entry['field'], _entry: Entry) { return CONDITION_FIELD_TITLE[field]; }, }, @@ -55,8 +55,8 @@ const getEntriesColumnDefinitions = (): Array sortable: false, truncateText: true, width: '20%', - render(field: Entry['operator'], entry: Entry) { - return OPERATOR_TITLES[field]; + render(_field: Entry['operator'], entry: Entry) { + return entry.type === 'wildcard' ? OPERATOR_TITLES.matches : OPERATOR_TITLES.is; }, }, { 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 7071022fb893f..f955e7b7dc568 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 @@ -11,7 +11,7 @@ import { MacosLinuxConditionEntry, WindowsConditionEntry, ConditionEntryField, - OperatorEntryField, + OperatorFieldIds, } from '../../../../../common/endpoint/types'; export { OS_TITLES } from '../../../common/translations'; @@ -52,19 +52,13 @@ export const CONDITION_FIELD_DESCRIPTION: { [K in ConditionEntryField]: string } ), }; -export const OPERATOR_TITLES: { [K in OperatorEntryField]: string } = { - [OperatorEntryField.included]: i18n.translate( - 'xpack.securitySolution.trustedapps.card.operator.is', - { - defaultMessage: 'is', - } - ), - [OperatorEntryField.wildcard_caseless]: i18n.translate( - 'xpack.securitySolution.trustedapps.card.operator.matches', - { - defaultMessage: 'matches', - } - ), +export const OPERATOR_TITLES: { [K in OperatorFieldIds]: string } = { + is: i18n.translate('xpack.securitySolution.trustedapps.card.operator.is', { + defaultMessage: 'is', + }), + matches: i18n.translate('xpack.securitySolution.trustedapps.card.operator.matches', { + defaultMessage: 'matches', + }), }; export const PROPERTY_TITLES: Readonly< diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts index cae1d9c27eb7f..a0ccef78ea0cf 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts @@ -9,12 +9,13 @@ import uuid from 'uuid'; import { OsType } from '../../../../../lists/common/schemas'; import { + Entry, EntriesArray, EntryMatch, + EntriesMatchWildcardCaseless, EntryNested, ExceptionListItemSchema, NestedEntriesArray, - Operator, } from '../../../../../lists/common'; import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/constants'; import { @@ -27,7 +28,6 @@ import { EffectScope, NewTrustedApp, OperatingSystem, - OperatorEntryField, TrustedApp, UpdateTrustedApp, } from '../../../../common/endpoint/types'; @@ -48,17 +48,18 @@ const OPERATING_SYSTEM_TO_OS_TYPE: Mapping = { }; const POLICY_REFERENCE_PREFIX = 'policy:'; +const OPERATOR_VALUE = 'included'; const filterUndefined = (list: Array): T[] => { return list.filter((item: T | undefined): item is T => item !== undefined); }; -export const createConditionEntry = ( +export const createConditionEntry = ( field: T, - operator: O, + type: Entry['type'], value: string ): ConditionEntry => { - return { field, value, type: 'match', operator }; + return { field, value, type, operator: OPERATOR_VALUE }; }; export const tagsToEffectScope = (tags: string[]): EffectScope => { @@ -76,46 +77,26 @@ export const tagsToEffectScope = (tags: string[]): EffectScope => { } }; -type TrustedAppsEntriesArray = Omit & { - operator: Operator | 'wildcard_caseless'; -}; - -export const entriesToConditionEntriesMap = ( - entries: TrustedAppsEntriesArray -): ConditionEntriesMap => { +export const entriesToConditionEntriesMap = (entries: EntriesArray): ConditionEntriesMap => { return entries.reduce((result, entry) => { if (entry.field.startsWith('process.hash') && entry.type === 'match') { return { ...result, [ConditionEntryField.HASH]: createConditionEntry( ConditionEntryField.HASH, - OperatorEntryField.included, - entry.value - ), - }; - } else if ( - entry.field === 'process.executable.caseless' && - entry.type === 'match' && - entry.operator === OperatorEntryField.wildcard_caseless - ) { - return { - ...result, - [ConditionEntryField.PATH]: createConditionEntry( - ConditionEntryField.PATH, - OperatorEntryField.wildcard_caseless, + entry.type, entry.value ), }; } else if ( entry.field === 'process.executable.caseless' && - entry.type === 'match' && - entry.operator === OperatorEntryField.included + (entry.type === 'match' || entry.type === 'wildcard') ) { return { ...result, [ConditionEntryField.PATH]: createConditionEntry( ConditionEntryField.PATH, - OperatorEntryField.included, + entry.type, entry.value ), }; @@ -129,7 +110,7 @@ export const entriesToConditionEntriesMap = ( ...result, [ConditionEntryField.SIGNER]: createConditionEntry( ConditionEntryField.SIGNER, - OperatorEntryField.included, + entry.type, subjectNameCondition.value ), }; @@ -200,12 +181,15 @@ const hashType = (hash: string): 'md5' | 'sha256' | 'sha1' | undefined => { } }; -export const createEntryMatch = ( +export const createEntryMatch = (field: string, value: string): EntryMatch => { + return { field, value, type: 'match', operator: OPERATOR_VALUE }; +}; + +export const createEntryMatchWildcardCaseless = ( field: string, - operator: OperatorEntryField, value: string -): EntryMatch => { - return { field, value, type: 'match', operator }; +): EntriesMatchWildcardCaseless => { + return { field, value, type: 'wildcard', operator: OPERATOR_VALUE }; }; export const createEntryNested = (field: string, entries: NestedEntriesArray): EntryNested => { @@ -225,29 +209,20 @@ export const conditionEntriesToEntries = (conditionEntries: ConditionEntry[]): E if (conditionEntry.field === ConditionEntryField.HASH) { return createEntryMatch( `process.hash.${hashType(conditionEntry.value)}`, - OperatorEntryField.included, conditionEntry.value.toLowerCase() ); } else if (conditionEntry.field === ConditionEntryField.SIGNER) { return createEntryNested(`process.Ext.code_signature`, [ - createEntryMatch('trusted', OperatorEntryField.included, 'true'), - createEntryMatch('subject_name', OperatorEntryField.included, conditionEntry.value), + createEntryMatch('trusted', 'true'), + createEntryMatch('subject_name', conditionEntry.value), ]); } else if ( conditionEntry.field === ConditionEntryField.PATH && - conditionEntry.operator === OperatorEntryField.wildcard_caseless + conditionEntry.type === 'wildcard' ) { - return createEntryMatch( - `process.executable.caseless`, - OperatorEntryField.wildcard_caseless, - conditionEntry.value - ); + return createEntryMatchWildcardCaseless(`process.executable.caseless`, conditionEntry.value); } else { - return createEntryMatch( - `process.executable.caseless`, - OperatorEntryField.included, - conditionEntry.value - ); + return createEntryMatch(`process.executable.caseless`, conditionEntry.value); } }); }; From 617aa7e119bb800efa454f5e95e7eb7d00480a87 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Mon, 26 Apr 2021 17:48:07 +0200 Subject: [PATCH 21/36] update tests refs elastic/security-team/issues/543 refs https://github.com/elastic/kibana/pull/97623#pullrequestreview-642618462 --- .../endpoint/schema/trusted_apps.test.ts | 8 +- .../routes/trusted_apps/handlers.test.ts | 25 +--- .../routes/trusted_apps/mapping.test.ts | 115 +++++------------- .../routes/trusted_apps/service.test.ts | 35 ++---- 4 files changed, 52 insertions(+), 131 deletions(-) diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts index 23f1d678e332a..df0d0d7acf4c7 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts @@ -247,24 +247,24 @@ describe('When invoking Trusted Apps Schema', () => { expect(() => body.validate(bodyMsg)).not.toThrow(); }); - it('should validate `entry.operator` does not accept `wildcard_caseless` when field is NOT PATH', () => { + it('should validate `entry.type` does not accept `wildcard` when field is NOT PATH', () => { const bodyMsg = createNewTrustedApp({ entries: [ createConditionEntry({ field: ConditionEntryField.HASH, - operator: 'wildcard_caseless', + type: 'wildcard', }), ], }); expect(() => body.validate(bodyMsg)).toThrow(); }); - it('should validate `entry.operator` accepts `wildcard_caseless` when field is PATH', () => { + it('should validate `entry.type` accepts `wildcard` when field is PATH', () => { const bodyMsg = createNewTrustedApp({ entries: [ createConditionEntry({ field: ConditionEntryField.PATH, - operator: 'wildcard_caseless', + type: 'wildcard', }), ], }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.test.ts index 700f676495ec6..0b4e1cb2b09b1 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.test.ts @@ -18,7 +18,6 @@ import { ConditionEntryField, NewTrustedApp, OperatingSystem, - OperatorEntryField, TrustedApp, } from '../../../../common/endpoint/types'; import { parseExperimentalConfigValue } from '../../../../common/experimental_features'; @@ -45,12 +44,8 @@ const EXCEPTION_LIST_ITEM: ExceptionListItemSchema = { created_by: 'admin', description: 'Linux trusted app 1', entries: [ - createEntryMatch('process.executable.caseless', OperatorEntryField.included, '/bin/malware'), - createEntryMatch( - 'process.hash.md5', - OperatorEntryField.included, - '1234234659af249ddf3e40864e9fb241' - ), + createEntryMatch('process.executable.caseless', '/bin/malware'), + createEntryMatch('process.hash.md5', '1234234659af249ddf3e40864e9fb241'), ], item_id: '123', list_id: 'endpoint_trusted_apps', @@ -71,12 +66,8 @@ const NEW_TRUSTED_APP: NewTrustedApp = { os: OperatingSystem.LINUX, effectScope: { type: 'global' }, entries: [ - createConditionEntry(ConditionEntryField.PATH, OperatorEntryField.included, '/bin/malware'), - createConditionEntry( - ConditionEntryField.HASH, - OperatorEntryField.included, - '1234234659af249ddf3e40864e9fb241' - ), + createConditionEntry(ConditionEntryField.PATH, 'match', '/bin/malware'), + createConditionEntry(ConditionEntryField.HASH, 'match', '1234234659af249ddf3e40864e9fb241'), ], }; @@ -92,12 +83,8 @@ const TRUSTED_APP: TrustedApp = { os: OperatingSystem.LINUX, effectScope: { type: 'global' }, entries: [ - createConditionEntry( - ConditionEntryField.HASH, - OperatorEntryField.included, - '1234234659af249ddf3e40864e9fb241' - ), - createConditionEntry(ConditionEntryField.PATH, OperatorEntryField.included, '/bin/malware'), + createConditionEntry(ConditionEntryField.HASH, 'match', '1234234659af249ddf3e40864e9fb241'), + createConditionEntry(ConditionEntryField.PATH, 'match', '/bin/malware'), ], }; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts index 689a83f06e281..679058ad5f62f 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts @@ -12,7 +12,6 @@ import { ConditionEntryField, NewTrustedApp, OperatingSystem, - OperatorEntryField, TrustedApp, UpdateTrustedApp, } from '../../../../common/endpoint/types'; @@ -80,13 +79,7 @@ describe('mapping', () => { description: 'Linux Trusted App', effectScope: { type: 'global' }, os: OperatingSystem.LINUX, - entries: [ - createConditionEntry( - ConditionEntryField.PATH, - OperatorEntryField.included, - '/bin/malware' - ), - ], + entries: [createConditionEntry(ConditionEntryField.PATH, 'match', '/bin/malware')], }, createExceptionListItemOptions({ name: 'linux trusted app', @@ -95,7 +88,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.executable.caseless', - OperatorEntryField.included, + '/bin/malware' ), ], @@ -110,13 +103,7 @@ describe('mapping', () => { description: 'MacOS Trusted App', effectScope: { type: 'global' }, os: OperatingSystem.MAC, - entries: [ - createConditionEntry( - ConditionEntryField.PATH, - OperatorEntryField.included, - '/bin/malware' - ), - ], + entries: [createConditionEntry(ConditionEntryField.PATH, 'match', '/bin/malware')], }, createExceptionListItemOptions({ name: 'macos trusted app', @@ -125,7 +112,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.executable.caseless', - OperatorEntryField.included, + '/bin/malware' ), ], @@ -141,11 +128,7 @@ describe('mapping', () => { effectScope: { type: 'global' }, os: OperatingSystem.WINDOWS, entries: [ - createConditionEntry( - ConditionEntryField.PATH, - OperatorEntryField.included, - 'C:\\Program Files\\Malware' - ), + createConditionEntry(ConditionEntryField.PATH, 'match', 'C:\\Program Files\\Malware'), ], }, createExceptionListItemOptions({ @@ -155,7 +138,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.executable.caseless', - OperatorEntryField.included, + 'C:\\Program Files\\Malware' ), ], @@ -170,13 +153,7 @@ describe('mapping', () => { description: 'Signed Trusted App', effectScope: { type: 'global' }, os: OperatingSystem.WINDOWS, - entries: [ - createConditionEntry( - ConditionEntryField.SIGNER, - OperatorEntryField.included, - 'Microsoft Windows' - ), - ], + entries: [createConditionEntry(ConditionEntryField.SIGNER, 'match', 'Microsoft Windows')], }, createExceptionListItemOptions({ name: 'Signed trusted app', @@ -184,8 +161,8 @@ describe('mapping', () => { osTypes: ['windows'], entries: [ createEntryNested('process.Ext.code_signature', [ - createEntryMatch('trusted', OperatorEntryField.included, 'true'), - createEntryMatch('subject_name', OperatorEntryField.included, 'Microsoft Windows'), + createEntryMatch('trusted', 'true'), + createEntryMatch('subject_name', 'Microsoft Windows'), ]), ], }) @@ -202,7 +179,7 @@ describe('mapping', () => { entries: [ createConditionEntry( ConditionEntryField.HASH, - OperatorEntryField.included, + 'match', '1234234659af249ddf3e40864e9fb241' ), ], @@ -214,7 +191,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.hash.md5', - OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' ), ], @@ -232,7 +209,7 @@ describe('mapping', () => { entries: [ createConditionEntry( ConditionEntryField.HASH, - OperatorEntryField.included, + 'match', 'f635da961234234659af249ddf3e40864e9fb241' ), ], @@ -244,7 +221,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.hash.sha1', - OperatorEntryField.included, + 'f635da961234234659af249ddf3e40864e9fb241' ), ], @@ -262,7 +239,7 @@ describe('mapping', () => { entries: [ createConditionEntry( ConditionEntryField.HASH, - OperatorEntryField.included, + 'match', 'f635da96124659af249ddf3e40864e9fb234234659af249ddf3e40864e9fb241' ), ], @@ -274,7 +251,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.hash.sha256', - OperatorEntryField.included, + 'f635da96124659af249ddf3e40864e9fb234234659af249ddf3e40864e9fb241' ), ], @@ -292,7 +269,7 @@ describe('mapping', () => { entries: [ createConditionEntry( ConditionEntryField.HASH, - OperatorEntryField.included, + 'match', '1234234659Af249ddf3e40864E9FB241' ), ], @@ -304,7 +281,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.hash.md5', - OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' ), ], @@ -330,7 +307,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.executable.caseless', - OperatorEntryField.included, + '/bin/malware' ), ], @@ -346,13 +323,7 @@ describe('mapping', () => { updated_at: '11/11/2011T11:11:11.111', updated_by: 'admin', os: OperatingSystem.LINUX, - entries: [ - createConditionEntry( - ConditionEntryField.PATH, - OperatorEntryField.included, - '/bin/malware' - ), - ], + entries: [createConditionEntry(ConditionEntryField.PATH, 'match', '/bin/malware')], } ); }); @@ -369,7 +340,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.executable.caseless', - OperatorEntryField.included, + '/bin/malware' ), ], @@ -385,13 +356,7 @@ describe('mapping', () => { updated_at: '11/11/2011T11:11:11.111', updated_by: 'admin', os: OperatingSystem.MAC, - entries: [ - createConditionEntry( - ConditionEntryField.PATH, - OperatorEntryField.included, - '/bin/malware' - ), - ], + entries: [createConditionEntry(ConditionEntryField.PATH, 'match', '/bin/malware')], } ); }); @@ -408,7 +373,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.executable.caseless', - OperatorEntryField.included, + 'C:\\Program Files\\Malware' ), ], @@ -425,11 +390,7 @@ describe('mapping', () => { updated_by: 'admin', os: OperatingSystem.WINDOWS, entries: [ - createConditionEntry( - ConditionEntryField.PATH, - OperatorEntryField.included, - 'C:\\Program Files\\Malware' - ), + createConditionEntry(ConditionEntryField.PATH, 'match', 'C:\\Program Files\\Malware'), ], } ); @@ -446,8 +407,8 @@ describe('mapping', () => { os_types: ['windows'], entries: [ createEntryNested('process.Ext.code_signature', [ - createEntryMatch('trusted', OperatorEntryField.included, 'true'), - createEntryMatch('subject_name', OperatorEntryField.included, 'Microsoft Windows'), + createEntryMatch('trusted', 'true'), + createEntryMatch('subject_name', 'Microsoft Windows'), ]), ], }), @@ -463,11 +424,7 @@ describe('mapping', () => { updated_by: 'admin', os: OperatingSystem.WINDOWS, entries: [ - createConditionEntry( - ConditionEntryField.SIGNER, - OperatorEntryField.included, - 'Microsoft Windows' - ), + createConditionEntry(ConditionEntryField.SIGNER, 'nested', 'Microsoft Windows'), ], } ); @@ -485,7 +442,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.hash.md5', - OperatorEntryField.included, + '1234234659af249ddf3e40864e9fb241' ), ], @@ -504,7 +461,7 @@ describe('mapping', () => { entries: [ createConditionEntry( ConditionEntryField.HASH, - OperatorEntryField.included, + 'match', '1234234659af249ddf3e40864e9fb241' ), ], @@ -524,7 +481,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.hash.sha1', - OperatorEntryField.included, + 'f635da961234234659af249ddf3e40864e9fb241' ), ], @@ -543,7 +500,7 @@ describe('mapping', () => { entries: [ createConditionEntry( ConditionEntryField.HASH, - OperatorEntryField.included, + 'match', 'f635da961234234659af249ddf3e40864e9fb241' ), ], @@ -563,7 +520,7 @@ describe('mapping', () => { entries: [ createEntryMatch( 'process.hash.sha256', - OperatorEntryField.included, + 'f635da96124659af249ddf3e40864e9fb234234659af249ddf3e40864e9fb241' ), ], @@ -582,7 +539,7 @@ describe('mapping', () => { entries: [ createConditionEntry( ConditionEntryField.HASH, - OperatorEntryField.included, + 'match', 'f635da96124659af249ddf3e40864e9fb234234659af249ddf3e40864e9fb241' ), ], @@ -598,13 +555,7 @@ describe('mapping', () => { description: 'Linux Trusted App', effectScope: { type: 'global' }, os: OperatingSystem.LINUX, - entries: [ - createConditionEntry( - ConditionEntryField.PATH, - OperatorEntryField.included, - '/bin/malware' - ), - ], + entries: [createConditionEntry(ConditionEntryField.PATH, 'match', '/bin/malware')], version: 'abc', }; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.test.ts index 1f4048d1fedc1..d99a89ce11137 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.test.ts @@ -11,7 +11,6 @@ import { ExceptionListClient } from '../../../../../lists/server'; import { ConditionEntryField, OperatingSystem, - OperatorEntryField, TrustedApp, } from '../../../../common/endpoint/types'; import { createConditionEntry, createEntryMatch } from './mapping'; @@ -38,12 +37,8 @@ const EXCEPTION_LIST_ITEM: ExceptionListItemSchema = { created_by: 'admin', description: 'Linux trusted app 1', entries: [ - createEntryMatch('process.executable.caseless', OperatorEntryField.included, '/bin/malware'), - createEntryMatch( - 'process.hash.md5', - OperatorEntryField.included, - '1234234659af249ddf3e40864e9fb241' - ), + createEntryMatch('process.executable.caseless', '/bin/malware'), + createEntryMatch('process.hash.md5', '1234234659af249ddf3e40864e9fb241'), ], item_id: '123', list_id: 'endpoint_trusted_apps', @@ -70,12 +65,8 @@ const TRUSTED_APP: TrustedApp = { os: OperatingSystem.LINUX, effectScope: { type: 'global' }, entries: [ - createConditionEntry( - ConditionEntryField.HASH, - OperatorEntryField.included, - '1234234659af249ddf3e40864e9fb241' - ), - createConditionEntry(ConditionEntryField.PATH, OperatorEntryField.included, '/bin/malware'), + createConditionEntry(ConditionEntryField.HASH, 'match', '1234234659af249ddf3e40864e9fb241'), + createConditionEntry(ConditionEntryField.PATH, 'match', '/bin/malware'), ], }; @@ -118,14 +109,10 @@ describe('service', () => { effectScope: { type: 'global' }, os: OperatingSystem.LINUX, entries: [ - createConditionEntry( - ConditionEntryField.PATH, - OperatorEntryField.included, - '/bin/malware' - ), + createConditionEntry(ConditionEntryField.PATH, 'match', '/bin/malware'), createConditionEntry( ConditionEntryField.HASH, - OperatorEntryField.included, + 'match', '1234234659af249ddf3e40864e9fb241' ), ], @@ -136,7 +123,7 @@ describe('service', () => { expect(exceptionsListClient.createTrustedAppsList).toHaveBeenCalled(); }); - it('should create trusted app with correct wildcard_caseless operator', async () => { + it('should create trusted app with correct wildcard type', async () => { exceptionsListClient.createExceptionListItem.mockResolvedValue(EXCEPTION_LIST_ITEM); const result = await createTrustedApp(exceptionsListClient, { @@ -145,14 +132,10 @@ describe('service', () => { effectScope: { type: 'global' }, os: OperatingSystem.LINUX, entries: [ - createConditionEntry( - ConditionEntryField.PATH, - OperatorEntryField.wildcard_caseless, - '/bin/malware' - ), + createConditionEntry(ConditionEntryField.PATH, 'wildcard', '/bin/malware'), createConditionEntry( ConditionEntryField.HASH, - OperatorEntryField.wildcard_caseless, + 'wildcard', '1234234659af249ddf3e40864e9fb241' ), ], From cc001e7a51a2e002993314ef875416e8d56e9e3d Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Mon, 26 Apr 2021 21:17:09 +0200 Subject: [PATCH 22/36] update name for wildcard type so that it can be used also for cased inputs refs elastic/security-team/issues/543 refs f9cb7eddda64e8198470cfb9f19a099c19e19dae --- x-pack/plugins/lists/common/schemas/types/entries.ts | 6 +++--- ...atch_wildcard_caseless.ts => entry_match_wildcard.ts} | 4 ++-- x-pack/plugins/lists/common/schemas/types/index.ts | 2 +- x-pack/plugins/lists/common/shared_exports.ts | 4 ++-- .../lists/public/exceptions/components/builder/types.ts | 6 +++--- .../plugins/security_solution/common/shared_imports.ts | 4 ++-- .../public/common/components/exceptions/types.ts | 6 +++--- .../server/endpoint/routes/trusted_apps/mapping.ts | 9 +++------ 8 files changed, 19 insertions(+), 22 deletions(-) rename x-pack/plugins/lists/common/schemas/types/{entry_match_wildcard_caseless.ts => entry_match_wildcard.ts} (78%) diff --git a/x-pack/plugins/lists/common/schemas/types/entries.ts b/x-pack/plugins/lists/common/schemas/types/entries.ts index 0ec7474a336b6..b483ef94168b3 100644 --- a/x-pack/plugins/lists/common/schemas/types/entries.ts +++ b/x-pack/plugins/lists/common/schemas/types/entries.ts @@ -12,7 +12,7 @@ import { entriesMatch } from './entry_match'; import { entriesExists } from './entry_exists'; import { entriesList } from './entry_list'; import { entriesNested } from './entry_nested'; -import { entriesMatchWildcardCaseless } from './entry_match_wildcard_caseless'; +import { entriesMatchWildcard } from './entry_match_wildcard'; export const entry = t.union([ entriesMatch, @@ -20,7 +20,7 @@ export const entry = t.union([ entriesList, entriesExists, entriesNested, - entriesMatchWildcardCaseless, + entriesMatchWildcard, ]); export type Entry = t.TypeOf; @@ -31,7 +31,7 @@ export const entriesArray = t.array( entriesList, entriesExists, entriesNested, - entriesMatchWildcardCaseless, + entriesMatchWildcard, ]) ); export type EntriesArray = t.TypeOf; diff --git a/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard_caseless.ts b/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.ts similarity index 78% rename from x-pack/plugins/lists/common/schemas/types/entry_match_wildcard_caseless.ts rename to x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.ts index f36ebdd8ac8ca..14522256df354 100644 --- a/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard_caseless.ts +++ b/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.ts @@ -10,7 +10,7 @@ import * as t from 'io-ts'; import { NonEmptyString } from '../../shared_imports'; import { operator } from '../common/schemas'; -export const entriesMatchWildcardCaseless = t.exact( +export const entriesMatchWildcard = t.exact( t.type({ field: NonEmptyString, operator, @@ -18,4 +18,4 @@ export const entriesMatchWildcardCaseless = t.exact( value: NonEmptyString, }) ); -export type EntriesMatchWildcardCaseless = t.TypeOf; +export type EntryMatchWildcard = t.TypeOf; diff --git a/x-pack/plugins/lists/common/schemas/types/index.ts b/x-pack/plugins/lists/common/schemas/types/index.ts index 01020752b2597..ebe21174570cb 100644 --- a/x-pack/plugins/lists/common/schemas/types/index.ts +++ b/x-pack/plugins/lists/common/schemas/types/index.ts @@ -15,7 +15,7 @@ export * from './default_namespace'; export * from './entries'; export * from './entry_match'; export * from './entry_match_any'; -export * from './entry_match_wildcard_caseless'; +export * from './entry_match_wildcard'; export * from './entry_list'; export * from './entry_exists'; export * from './entry_nested'; diff --git a/x-pack/plugins/lists/common/shared_exports.ts b/x-pack/plugins/lists/common/shared_exports.ts index 8fcf611ccd7e1..4a20a8775aef2 100644 --- a/x-pack/plugins/lists/common/shared_exports.ts +++ b/x-pack/plugins/lists/common/shared_exports.ts @@ -20,7 +20,7 @@ export { EntryExists, EntryMatch, EntryMatchAny, - EntriesMatchWildcardCaseless, + EntryMatchWildcard, EntryNested, EntryList, EntriesArray, @@ -40,7 +40,7 @@ export { nestedEntryItem, entriesMatch, entriesMatchAny, - entriesMatchWildcardCaseless, + entriesMatchWildcard, entriesExists, entriesList, namespaceType, diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/types.ts b/x-pack/plugins/lists/public/exceptions/components/builder/types.ts index 5ac72b3ef546f..800f1445217b9 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/types.ts +++ b/x-pack/plugins/lists/public/exceptions/components/builder/types.ts @@ -9,11 +9,11 @@ import { IFieldType } from '../../../../../../../src/plugins/data/common'; import { OperatorOption } from '../autocomplete/types'; import { CreateExceptionListItemSchema, - EntriesMatchWildcardCaseless, Entry, EntryExists, EntryMatch, EntryMatchAny, + EntryMatchWildcard, EntryNested, ExceptionListItemSchema, OperatorEnum, @@ -54,7 +54,7 @@ export interface EmptyNestedEntry { entries: Array< | (EntryMatch & { id?: string }) | (EntryMatchAny & { id?: string }) - | (EntriesMatchWildcardCaseless & { id?: string }) + | (EntryMatchWildcard & { id?: string }) | (EntryExists & { id?: string }) >; } @@ -71,7 +71,7 @@ export type BuilderEntryNested = Omit & { entries: Array< | (EntryMatch & { id?: string }) | (EntryMatchAny & { id?: string }) - | (EntriesMatchWildcardCaseless & { id?: string }) + | (EntryMatchWildcard & { id?: string }) | (EntryExists & { id?: string }) >; }; diff --git a/x-pack/plugins/security_solution/common/shared_imports.ts b/x-pack/plugins/security_solution/common/shared_imports.ts index f02cc472e9f60..a1d80177b389f 100644 --- a/x-pack/plugins/security_solution/common/shared_imports.ts +++ b/x-pack/plugins/security_solution/common/shared_imports.ts @@ -20,7 +20,7 @@ export { EntryExists, EntryMatch, EntryMatchAny, - EntriesMatchWildcardCaseless, + EntryMatchWildcard, EntryNested, EntryList, EntriesArray, @@ -39,7 +39,7 @@ export { nestedEntryItem, entriesMatch, entriesMatchAny, - entriesMatchWildcardCaseless, + entriesMatchWildcard, entriesExists, entriesList, namespaceType, diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/types.ts b/x-pack/plugins/security_solution/public/common/components/exceptions/types.ts index 7bce9f0b557b2..92a3cb2cfac93 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/types.ts +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/types.ts @@ -15,7 +15,7 @@ import { Entry, EntryMatch, EntryMatchAny, - EntriesMatchWildcardCaseless, + EntryMatchWildcard, EntryExists, ExceptionListItemSchema, CreateExceptionListItemSchema, @@ -93,7 +93,7 @@ export interface EmptyNestedEntry { type: OperatorTypeEnum.NESTED; entries: Array< | (EntryMatch & { id?: string }) - | (EntriesMatchWildcardCaseless & { id?: string }) + | (EntryMatchWildcard & { id?: string }) | (EntryMatchAny & { id?: string }) | (EntryExists & { id?: string }) >; @@ -110,7 +110,7 @@ export type BuilderEntryNested = Omit & { id?: string; entries: Array< | (EntryMatch & { id?: string }) - | (EntriesMatchWildcardCaseless & { id?: string }) + | (EntryMatchWildcard & { id?: string }) | (EntryMatchAny & { id?: string }) | (EntryExists & { id?: string }) >; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts index a0ccef78ea0cf..92f49026cd684 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts @@ -12,7 +12,7 @@ import { Entry, EntriesArray, EntryMatch, - EntriesMatchWildcardCaseless, + EntryMatchWildcard, EntryNested, ExceptionListItemSchema, NestedEntriesArray, @@ -185,10 +185,7 @@ export const createEntryMatch = (field: string, value: string): EntryMatch => { return { field, value, type: 'match', operator: OPERATOR_VALUE }; }; -export const createEntryMatchWildcardCaseless = ( - field: string, - value: string -): EntriesMatchWildcardCaseless => { +export const createEntryMatchWildcard = (field: string, value: string): EntryMatchWildcard => { return { field, value, type: 'wildcard', operator: OPERATOR_VALUE }; }; @@ -220,7 +217,7 @@ export const conditionEntriesToEntries = (conditionEntries: ConditionEntry[]): E conditionEntry.field === ConditionEntryField.PATH && conditionEntry.type === 'wildcard' ) { - return createEntryMatchWildcardCaseless(`process.executable.caseless`, conditionEntry.value); + return createEntryMatchWildcard(`process.executable.caseless`, conditionEntry.value); } else { return createEntryMatch(`process.executable.caseless`, conditionEntry.value); } From 6a874c07e22845eaa0bf1bb5547244f797c284f7 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Tue, 27 Apr 2021 11:07:39 +0200 Subject: [PATCH 23/36] update artifacts to support wildcard entries refs elastic/security-team/issues/543 --- .../server/endpoint/lib/artifacts/lists.ts | 17 +++++++++++++++++ .../endpoint/schemas/artifacts/lists.ts | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts index 1c3c92c50afd3..54b6971eec58e 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts @@ -22,6 +22,8 @@ import { translatedEntryMatchAnyMatcher, TranslatedEntryMatcher, translatedEntryMatchMatcher, + TranslatedEntryMatchWildcardMatcher, + translatedEntryMatchWildcardMatcher, TranslatedEntryNestedEntry, translatedEntryNestedEntry, TranslatedExceptionListItem, @@ -203,6 +205,10 @@ function getMatcherFunction(field: string, matchAny?: boolean): TranslatedEntryM : 'exact_cased'; } +function getMatcherWildcardFunction(field: string): TranslatedEntryMatchWildcardMatcher { + return field.endsWith('.caseless') ? 'wildcard_caseless' : 'wildcard_cased'; +} + function normalizeFieldName(field: string): string { return field.endsWith('.caseless') ? field.substring(0, field.lastIndexOf('.')) : field; } @@ -272,6 +278,17 @@ function translateEntry( } : undefined; } + case 'wildcard': { + const matcher = getMatcherWildcardFunction(entry.field); + return translatedEntryMatchWildcardMatcher.is(matcher) + ? { + field: normalizeFieldName(entry.field), + operator: entry.operator, + type: matcher, + value: entry.value, + } + : undefined; + } } } diff --git a/x-pack/plugins/security_solution/server/endpoint/schemas/artifacts/lists.ts b/x-pack/plugins/security_solution/server/endpoint/schemas/artifacts/lists.ts index 4c11325652f80..1b1370472f633 100644 --- a/x-pack/plugins/security_solution/server/endpoint/schemas/artifacts/lists.ts +++ b/x-pack/plugins/security_solution/server/endpoint/schemas/artifacts/lists.ts @@ -30,6 +30,24 @@ export const translatedEntryMatchMatcher = t.keyof({ }); export type TranslatedEntryMatchMatcher = t.TypeOf; +export const translatedEntryMatchWildcardMatcher = t.keyof({ + wildcard_cased: null, + wildcard_caseless: null, +}); +export type TranslatedEntryMatchWildcardMatcher = t.TypeOf< + typeof translatedEntryMatchWildcardMatcher +>; + +export const translatedEntryMatchWildcard = t.exact( + t.type({ + field: t.string, + operator, + type: translatedEntryMatchWildcardMatcher, + value: t.string, + }) +); +export type TranslatedEntryMatchWildcard = t.TypeOf; + export const translatedEntryMatch = t.exact( t.type({ field: t.string, @@ -61,6 +79,7 @@ export type TranslatedEntryNested = t.TypeOf; export const translatedEntry = t.union([ translatedEntryNested, translatedEntryMatch, + translatedEntryMatchWildcard, translatedEntryMatchAny, ]); export type TranslatedEntry = t.TypeOf; From b2cf2236b99ab2e0f60a0c76e0dd2604962a8cf6 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Tue, 27 Apr 2021 13:49:24 +0200 Subject: [PATCH 24/36] add tests for list schemas refs f9cb7eddda64e8198470cfb9f19a099c19e19dae refs elastic/security-team/issues/543 --- x-pack/plugins/lists/common/constants.mock.ts | 1 + .../types/endpoint/entry_match_wildcard.ts | 21 ++++ .../types/entry_match_wildcard.mock.ts | 22 ++++ .../types/entry_match_wildcard.test.ts | 106 ++++++++++++++++++ 4 files changed, 150 insertions(+) create mode 100644 x-pack/plugins/lists/common/schemas/types/endpoint/entry_match_wildcard.ts create mode 100644 x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.mock.ts create mode 100644 x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.test.ts diff --git a/x-pack/plugins/lists/common/constants.mock.ts b/x-pack/plugins/lists/common/constants.mock.ts index 27e0fa29b1e55..177f0a4b291d5 100644 --- a/x-pack/plugins/lists/common/constants.mock.ts +++ b/x-pack/plugins/lists/common/constants.mock.ts @@ -51,6 +51,7 @@ export const OPERATOR_EXCLUDED = 'excluded'; export const ENTRY_VALUE = 'some host name'; export const MATCH = 'match'; export const MATCH_ANY = 'match_any'; +export const WILDCARD = 'wildcard'; export const MAX_IMPORT_PAYLOAD_BYTES = 9000000; export const IMPORT_BUFFER_SIZE = 1000; export const LIST = 'list'; diff --git a/x-pack/plugins/lists/common/schemas/types/endpoint/entry_match_wildcard.ts b/x-pack/plugins/lists/common/schemas/types/endpoint/entry_match_wildcard.ts new file mode 100644 index 0000000000000..dfcaa963666de --- /dev/null +++ b/x-pack/plugins/lists/common/schemas/types/endpoint/entry_match_wildcard.ts @@ -0,0 +1,21 @@ +/* + * 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 * as t from 'io-ts'; + +import { NonEmptyString } from '../../../shared_imports'; +import { operatorIncluded } from '../../common/schemas'; + +export const endpointEntryMatchWildcard = t.exact( + t.type({ + field: NonEmptyString, + operator: operatorIncluded, + type: t.keyof({ wildcard: null }), + value: NonEmptyString, + }) +); +export type EndpointEntryMatchWildcard = t.TypeOf; diff --git a/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.mock.ts b/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.mock.ts new file mode 100644 index 0000000000000..3204bbe064496 --- /dev/null +++ b/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.mock.ts @@ -0,0 +1,22 @@ +/* + * 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 { ENTRY_VALUE, FIELD, OPERATOR, WILDCARD } from '../../constants.mock'; + +import { EntryMatchWildcard } from './entry_match_wildcard'; + +export const getEntryMatchWildcardMock = (): EntryMatchWildcard => ({ + field: FIELD, + operator: OPERATOR, + type: WILDCARD, + value: ENTRY_VALUE, +}); + +export const getEntryMatchWildcardExcludeMock = (): EntryMatchWildcard => ({ + ...getEntryMatchWildcardMock(), + operator: 'excluded', +}); diff --git a/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.test.ts b/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.test.ts new file mode 100644 index 0000000000000..53cfc4fdff1f5 --- /dev/null +++ b/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.test.ts @@ -0,0 +1,106 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; + +import { foldLeftRight, getPaths } from '../../shared_imports'; + +import { getEntryMatchWildcardMock } from './entry_match_wildcard.mock'; +import { EntryMatchWildcard, entriesMatchWildcard } from './entry_match_wildcard'; + +describe('entriesMatchWildcard', () => { + test('it should validate an entry', () => { + const payload = getEntryMatchWildcardMock(); + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when operator is "included"', () => { + const payload = getEntryMatchWildcardMock(); + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when "operator" is "excluded"', () => { + const payload = getEntryMatchWildcardMock(); + payload.operator = 'excluded'; + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation when "field" is empty string', () => { + const payload: Omit & { field: string } = { + ...getEntryMatchWildcardMock(), + field: '', + }; + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "value" is not string', () => { + const payload: Omit & { value: string[] } = { + ...getEntryMatchWildcardMock(), + value: ['some value'], + }; + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "["some value"]" supplied to "value"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "value" is empty string', () => { + const payload: Omit & { value: string } = { + ...getEntryMatchWildcardMock(), + value: '', + }; + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "value"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "type" is not "wildcard"', () => { + const payload: Omit & { type: string } = { + ...getEntryMatchWildcardMock(), + type: 'match', + }; + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: EntryMatchWildcard & { + extraKey?: string; + } = getEntryMatchWildcardMock(); + payload.extraKey = 'some value'; + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getEntryMatchWildcardMock()); + }); +}); From 6f2d0d78104673a4b18a6c0d04a93842ffaf06a5 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Tue, 27 Apr 2021 16:06:05 +0200 Subject: [PATCH 25/36] add placeholders for path values review changes elastic/kibana/pull/97623#discussion_r620617999 --- .../view/components/condition_entry_input/index.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index ba14b8c9beec9..8314cdce9b38f 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -191,6 +191,17 @@ export const ConditionEntryInput = memo( Date: Tue, 27 Apr 2021 17:29:41 +0200 Subject: [PATCH 26/36] ignore type check for now --- .../lists/public/exceptions/components/builder/helpers.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/helpers.ts b/x-pack/plugins/lists/public/exceptions/components/builder/helpers.ts index 4cf9f233f3917..120674cff9f02 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/helpers.ts +++ b/x-pack/plugins/lists/public/exceptions/components/builder/helpers.ts @@ -583,6 +583,7 @@ export const getEntryOnOperatorChange = ( index: parent.parentIndex, updatedEntry: { ...parent.parent, + // @ts-expect-error entries: [ ...parent.parent.entries.slice(0, entryIndex), { From bcf615ac9810edfef0f5037cbd8a82b6972a05dc Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Tue, 27 Apr 2021 17:41:28 +0200 Subject: [PATCH 27/36] add type assertion refs 284352ec9a00041cd261bc69a3207708a2e80ef2 --- .../lists/public/exceptions/components/builder/helpers.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/helpers.ts b/x-pack/plugins/lists/public/exceptions/components/builder/helpers.ts index 120674cff9f02..c91665f84f815 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/helpers.ts +++ b/x-pack/plugins/lists/public/exceptions/components/builder/helpers.ts @@ -583,7 +583,6 @@ export const getEntryOnOperatorChange = ( index: parent.parentIndex, updatedEntry: { ...parent.parent, - // @ts-expect-error entries: [ ...parent.parent.entries.slice(0, entryIndex), { @@ -592,7 +591,7 @@ export const getEntryOnOperatorChange = ( }, ...parent.parent.entries.slice(entryIndex + 1), ], - }, + } as BuilderEntry, }; } else { return { index: entryIndex, updatedEntry: newEntry }; From 835812fb266dea87903774e61167db299a98673f Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Tue, 27 Apr 2021 17:50:46 +0200 Subject: [PATCH 28/36] remove unnecessary test refs 2ac56ee839342c520928487b4a49f25938fa08ca --- .../plugins/lists/common/schemas/common/schemas.test.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/x-pack/plugins/lists/common/schemas/common/schemas.test.ts b/x-pack/plugins/lists/common/schemas/common/schemas.test.ts index 69cf794b5575d..9f3abb9259f6c 100644 --- a/x-pack/plugins/lists/common/schemas/common/schemas.test.ts +++ b/x-pack/plugins/lists/common/schemas/common/schemas.test.ts @@ -53,15 +53,6 @@ describe('Common schemas', () => { expect(message.schema).toEqual(payload); }); - test('it should validate for "wildcard_caseless"', () => { - const payload = 'wildcard_caseless'; - const decoded = operator.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - test('it should contain same amount of keys as enum', () => { // Might seem like a weird test, but its meant to // ensure that if operator is updated, you From dbd353214930afd5f0b4bb14ffebb94904a9c477 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Tue, 27 Apr 2021 22:29:41 +0200 Subject: [PATCH 29/36] fix types refs f9cb7eddda64e8198470cfb9f19a099c19e19dae refs b3f5dc45539da80e66f5ae8240737717f2a14766 --- x-pack/plugins/lists/common/schemas/types/entries.ts | 1 - .../security_solution/common/endpoint/types/trusted_apps.ts | 4 ++-- .../server/endpoint/routes/trusted_apps/mapping.test.ts | 4 +--- .../server/endpoint/routes/trusted_apps/mapping.ts | 6 +++--- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/lists/common/schemas/types/entries.ts b/x-pack/plugins/lists/common/schemas/types/entries.ts index b483ef94168b3..96d4bc22f55af 100644 --- a/x-pack/plugins/lists/common/schemas/types/entries.ts +++ b/x-pack/plugins/lists/common/schemas/types/entries.ts @@ -19,7 +19,6 @@ export const entry = t.union([ entriesMatchAny, entriesList, entriesExists, - entriesNested, entriesMatchWildcard, ]); export type Entry = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts index 3c854dbb7bd72..8d66370fea4d3 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts @@ -8,7 +8,6 @@ import { TypeOf } from '@kbn/config-schema'; import { ApplicationStart } from 'kibana/public'; -import { Entry } from '../../../../lists/common/schemas/types/entries'; import { DeleteTrustedAppsRequestSchema, GetOneTrustedAppRequestSchema, @@ -76,9 +75,10 @@ export enum OperatorFieldIds { matches = 'matches', } +export type TrustedAppEntryTypes = 'match' | 'wildcard'; export interface ConditionEntry { field: T; - type: Entry['type']; + type: TrustedAppEntryTypes; operator: 'included'; value: string; } diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts index 679058ad5f62f..9ee2ece627841 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.test.ts @@ -423,9 +423,7 @@ describe('mapping', () => { updated_at: '11/11/2011T11:11:11.111', updated_by: 'admin', os: OperatingSystem.WINDOWS, - entries: [ - createConditionEntry(ConditionEntryField.SIGNER, 'nested', 'Microsoft Windows'), - ], + entries: [createConditionEntry(ConditionEntryField.SIGNER, 'match', 'Microsoft Windows')], } ); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts index 92f49026cd684..786a74e91b51a 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts @@ -9,7 +9,6 @@ import uuid from 'uuid'; import { OsType } from '../../../../../lists/common/schemas'; import { - Entry, EntriesArray, EntryMatch, EntryMatchWildcard, @@ -30,6 +29,7 @@ import { OperatingSystem, TrustedApp, UpdateTrustedApp, + TrustedAppEntryTypes, } from '../../../../common/endpoint/types'; type ConditionEntriesMap = { [K in ConditionEntryField]?: ConditionEntry }; @@ -56,7 +56,7 @@ const filterUndefined = (list: Array): T[] => { export const createConditionEntry = ( field: T, - type: Entry['type'], + type: TrustedAppEntryTypes, value: string ): ConditionEntry => { return { field, value, type, operator: OPERATOR_VALUE }; @@ -110,7 +110,7 @@ export const entriesToConditionEntriesMap = (entries: EntriesArray): ConditionEn ...result, [ConditionEntryField.SIGNER]: createConditionEntry( ConditionEntryField.SIGNER, - entry.type, + subjectNameCondition.type, subjectNameCondition.value ), }; From ddc3d72c805ed7f25fe7f2184bb98d51ca8426d6 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Wed, 28 Apr 2021 08:39:38 +0200 Subject: [PATCH 30/36] add a note to entries review changes refs dbd353214930afd5f0b4bb14ffebb94904a9c477 --- x-pack/plugins/lists/common/schemas/types/entries.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/lists/common/schemas/types/entries.ts b/x-pack/plugins/lists/common/schemas/types/entries.ts index 96d4bc22f55af..26cfed568cea8 100644 --- a/x-pack/plugins/lists/common/schemas/types/entries.ts +++ b/x-pack/plugins/lists/common/schemas/types/entries.ts @@ -14,6 +14,8 @@ import { entriesList } from './entry_list'; import { entriesNested } from './entry_nested'; import { entriesMatchWildcard } from './entry_match_wildcard'; +// NOTE: Type nested is not included here to denote it's non-recursive nature. +// So a nested entry is really just a collection of `Entry` types. export const entry = t.union([ entriesMatch, entriesMatchAny, From 0bf81993a3645cb4a493fa82e717bec675ba0ecc Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Wed, 28 Apr 2021 08:44:21 +0200 Subject: [PATCH 31/36] remove redundant type assertions review changes refs bcf615ac9810edfef0f5037cbd8a82b6972a05dc refs b3f5dc45539da80e66f5ae8240737717f2a14766 --- .../lists/public/exceptions/components/builder/helpers.ts | 2 +- .../security_solution/common/endpoint/schema/trusted_apps.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/helpers.ts b/x-pack/plugins/lists/public/exceptions/components/builder/helpers.ts index c91665f84f815..4cf9f233f3917 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/helpers.ts +++ b/x-pack/plugins/lists/public/exceptions/components/builder/helpers.ts @@ -591,7 +591,7 @@ export const getEntryOnOperatorChange = ( }, ...parent.parent.entries.slice(entryIndex + 1), ], - } as BuilderEntry, + }, }; } else { return { index: entryIndex, updatedEntry: newEntry }; diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts index 9858f2a72c2d0..54d0becd2446e 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts @@ -35,7 +35,7 @@ const ConditionEntryTypeSchema = schema.conditional( schema.oneOf([schema.literal('match'), schema.literal('wildcard')]), schema.literal('match') ); -const ConditionEntryOperatorSchema = schema.literal('included' as ConditionEntry['operator']); +const ConditionEntryOperatorSchema = schema.literal('included'); /* * A generic Entry schema to be used for a specific entry schema depending on the OS From 2dc4fd390cf5ea0e4fa67b3f5fc2561cbb29555e Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Wed, 28 Apr 2021 11:38:55 +0200 Subject: [PATCH 32/36] move placeholder text logic to utils review changes elastic/kibana/pull/97623#discussion_r621673881 refs 6f2d0d78104673a4b18a6c0d04a93842ffaf06a5 --- .../common/utils/path_placeholder.test.ts | 69 +++++++++++++++++++ .../common/utils/path_placeholder.ts | 43 ++++++++++++ .../condition_entry_input/index.tsx | 17 ++--- 3 files changed, 118 insertions(+), 11 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/utils/path_placeholder.test.ts create mode 100644 x-pack/plugins/security_solution/common/utils/path_placeholder.ts diff --git a/x-pack/plugins/security_solution/common/utils/path_placeholder.test.ts b/x-pack/plugins/security_solution/common/utils/path_placeholder.test.ts new file mode 100644 index 0000000000000..f79a164e7d4fe --- /dev/null +++ b/x-pack/plugins/security_solution/common/utils/path_placeholder.test.ts @@ -0,0 +1,69 @@ +/* + * 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 { getPlaceholderText, placeholderText } from './path_placeholder'; +import { ConditionEntryField, OperatingSystem, TrustedAppEntryTypes } from '../endpoint/types'; + +const trustedAppEntry = { + os: OperatingSystem.LINUX, + field: ConditionEntryField.HASH, + type: 'match' as TrustedAppEntryTypes, +}; + +describe('Trusted Apps: Path placeholder text', () => { + it('returns no placeholder text when field IS NOT PATH', () => { + expect(getPlaceholderText({ ...trustedAppEntry })).toEqual(undefined); + }); + + it('returns a placeholder text when field IS PATH', () => { + expect(getPlaceholderText({ ...trustedAppEntry, field: ConditionEntryField.PATH })).toEqual( + placeholderText.others.exact + ); + }); + + it('returns LINUX/MAC equivalent placholder when field IS PATH', () => { + expect( + getPlaceholderText({ + ...trustedAppEntry, + os: OperatingSystem.MAC, + field: ConditionEntryField.PATH, + }) + ).toEqual(placeholderText.others.exact); + }); + + it('returns LINUX/MAC equivalent placholder text when field IS PATH and WILDCARD operator is selected', () => { + expect( + getPlaceholderText({ + ...trustedAppEntry, + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'wildcard', + }) + ).toEqual(placeholderText.others.wildcard); + }); + + it('returns WINDOWS equivalent placholder text when field IS PATH', () => { + expect( + getPlaceholderText({ + ...trustedAppEntry, + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + }) + ).toEqual(placeholderText.windows.exact); + }); + + it('returns WINDOWS equivalent placholder text when field IS PATH and WILDCARD operator is selected', () => { + expect( + getPlaceholderText({ + ...trustedAppEntry, + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + }) + ).toEqual(placeholderText.windows.wildcard); + }); +}); diff --git a/x-pack/plugins/security_solution/common/utils/path_placeholder.ts b/x-pack/plugins/security_solution/common/utils/path_placeholder.ts new file mode 100644 index 0000000000000..ee38ec11781d1 --- /dev/null +++ b/x-pack/plugins/security_solution/common/utils/path_placeholder.ts @@ -0,0 +1,43 @@ +/* + * 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 { ConditionEntryField, OperatingSystem, TrustedAppEntryTypes } from '../endpoint/types'; + +export const placeholderText = { + windows: { + wildcard: 'C:\\sample\\**\\*', + exact: 'C:\\sample\\path.exe', + }, + others: { + wildcard: '/opt/**/*', + exact: '/opt/bin', + }, +}; + +export const getPlaceholderText = ({ + os, + field, + type, +}: { + os: OperatingSystem; + field: ConditionEntryField; + type: TrustedAppEntryTypes; +}): string | undefined => { + if (field === ConditionEntryField.PATH) { + if (os === OperatingSystem.WINDOWS) { + if (type === 'wildcard') { + return placeholderText.windows.wildcard; + } + return placeholderText.windows.exact; + } else { + if (type === 'wildcard') { + return placeholderText.others.wildcard; + } + return placeholderText.others.exact; + } + } +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index 8314cdce9b38f..1f2892116908e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -31,6 +31,7 @@ import { OPERATOR_TITLES, } from '../../translations'; import { useTestIdGenerator } from '../../../../../components/hooks/use_test_id_generator'; +import { getPlaceholderText } from '../../../../../../../common/utils/path_placeholder'; const ConditionEntryCell = memo<{ showLabel: boolean; @@ -191,17 +192,11 @@ export const ConditionEntryInput = memo( Date: Wed, 28 Apr 2021 13:15:05 +0200 Subject: [PATCH 33/36] pass the style as prop review changes --- .../view/components/condition_entry_input/index.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index 1f2892116908e..7915e3ed30bae 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -75,7 +75,8 @@ const InputGroup = styled.div` grid-template-areas: 'field operator value remove'; `; -const InputItem = styled.div` +const InputItem = styled.div<{ gridArea: string }>` + grid-area: ${({ gridArea }) => gridArea}; align-self: center; margin: 4px; vertical-align: baseline; @@ -158,7 +159,7 @@ export const ConditionEntryInput = memo( return ( - + ( /> - + {entry.field === ConditionEntryField.PATH ? ( ( )} - + ( /> - + {/* Unicode `nbsp` is used below so that Remove button is property displayed */} Date: Wed, 28 Apr 2021 14:44:57 +0200 Subject: [PATCH 34/36] update api doc CI check suggestion --- api_docs/security_solution.json | 38 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/api_docs/security_solution.json b/api_docs/security_solution.json index aea50fdbfecaa..1e932a807d7d6 100644 --- a/api_docs/security_solution.json +++ b/api_docs/security_solution.json @@ -207,7 +207,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 353 + "lineNumber": 346 } }, { @@ -221,7 +221,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 353 + "lineNumber": 346 } } ], @@ -229,7 +229,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 353 + "lineNumber": 346 } }, { @@ -245,7 +245,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/security_solution/public/plugin.tsx", - "lineNumber": 398 + "lineNumber": 391 } } ], @@ -276,7 +276,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/public/types.ts", - "lineNumber": 69 + "lineNumber": 68 }, "signature": [ "() => Promise<", @@ -287,7 +287,7 @@ ], "source": { "path": "x-pack/plugins/security_solution/public/types.ts", - "lineNumber": 68 + "lineNumber": 67 }, "lifecycle": "setup", "initialIsOpen": true @@ -301,7 +301,7 @@ "children": [], "source": { "path": "x-pack/plugins/security_solution/public/types.ts", - "lineNumber": 72 + "lineNumber": 71 }, "lifecycle": "start", "initialIsOpen": true @@ -453,7 +453,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 147 + "lineNumber": 145 } } ], @@ -461,7 +461,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 147 + "lineNumber": 145 } }, { @@ -521,7 +521,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 159 + "lineNumber": 157 } }, { @@ -535,7 +535,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 159 + "lineNumber": 157 } } ], @@ -543,7 +543,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 159 + "lineNumber": 157 } }, { @@ -582,7 +582,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 341 + "lineNumber": 338 } }, { @@ -596,7 +596,7 @@ "description": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 341 + "lineNumber": 338 } } ], @@ -604,7 +604,7 @@ "returnComment": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 341 + "lineNumber": 338 } }, { @@ -620,13 +620,13 @@ "returnComment": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 423 + "lineNumber": 412 } } ], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 131 + "lineNumber": 129 }, "initialIsOpen": false } @@ -1484,7 +1484,7 @@ "children": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 107 + "lineNumber": 105 }, "lifecycle": "setup", "initialIsOpen": true @@ -1498,7 +1498,7 @@ "children": [], "source": { "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 110 + "lineNumber": 108 }, "lifecycle": "start", "initialIsOpen": true From 330731ebfcfd356707b5ff38d60106e6f1e409d9 Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Thu, 29 Apr 2021 10:51:43 +0200 Subject: [PATCH 35/36] make placeholderText a function expression review suggestion elastic/kibana/pull/97623/commits/2dc4fd390cf5ea0e4fa67b3f5fc2561cbb29555e --- .../common/utils/path_placeholder.test.ts | 12 ++++++------ .../common/utils/path_placeholder.ts | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/security_solution/common/utils/path_placeholder.test.ts b/x-pack/plugins/security_solution/common/utils/path_placeholder.test.ts index f79a164e7d4fe..50bf0d670a109 100644 --- a/x-pack/plugins/security_solution/common/utils/path_placeholder.test.ts +++ b/x-pack/plugins/security_solution/common/utils/path_placeholder.test.ts @@ -21,7 +21,7 @@ describe('Trusted Apps: Path placeholder text', () => { it('returns a placeholder text when field IS PATH', () => { expect(getPlaceholderText({ ...trustedAppEntry, field: ConditionEntryField.PATH })).toEqual( - placeholderText.others.exact + placeholderText().others.exact ); }); @@ -32,7 +32,7 @@ describe('Trusted Apps: Path placeholder text', () => { os: OperatingSystem.MAC, field: ConditionEntryField.PATH, }) - ).toEqual(placeholderText.others.exact); + ).toEqual(placeholderText().others.exact); }); it('returns LINUX/MAC equivalent placholder text when field IS PATH and WILDCARD operator is selected', () => { @@ -43,7 +43,7 @@ describe('Trusted Apps: Path placeholder text', () => { field: ConditionEntryField.PATH, type: 'wildcard', }) - ).toEqual(placeholderText.others.wildcard); + ).toEqual(placeholderText().others.wildcard); }); it('returns WINDOWS equivalent placholder text when field IS PATH', () => { @@ -53,10 +53,10 @@ describe('Trusted Apps: Path placeholder text', () => { os: OperatingSystem.WINDOWS, field: ConditionEntryField.PATH, }) - ).toEqual(placeholderText.windows.exact); + ).toEqual(placeholderText().windows.exact); }); - it('returns WINDOWS equivalent placholder text when field IS PATH and WILDCARD operator is selected', () => { + it('returns WINDOWS equivalent placeholder text when field IS PATH and WILDCARD operator is selected', () => { expect( getPlaceholderText({ ...trustedAppEntry, @@ -64,6 +64,6 @@ describe('Trusted Apps: Path placeholder text', () => { field: ConditionEntryField.PATH, type: 'wildcard', }) - ).toEqual(placeholderText.windows.wildcard); + ).toEqual(placeholderText().windows.wildcard); }); }); diff --git a/x-pack/plugins/security_solution/common/utils/path_placeholder.ts b/x-pack/plugins/security_solution/common/utils/path_placeholder.ts index ee38ec11781d1..d87934b97908a 100644 --- a/x-pack/plugins/security_solution/common/utils/path_placeholder.ts +++ b/x-pack/plugins/security_solution/common/utils/path_placeholder.ts @@ -7,7 +7,7 @@ import { ConditionEntryField, OperatingSystem, TrustedAppEntryTypes } from '../endpoint/types'; -export const placeholderText = { +export const placeholderText = () => ({ windows: { wildcard: 'C:\\sample\\**\\*', exact: 'C:\\sample\\path.exe', @@ -16,7 +16,7 @@ export const placeholderText = { wildcard: '/opt/**/*', exact: '/opt/bin', }, -}; +}); export const getPlaceholderText = ({ os, @@ -30,14 +30,14 @@ export const getPlaceholderText = ({ if (field === ConditionEntryField.PATH) { if (os === OperatingSystem.WINDOWS) { if (type === 'wildcard') { - return placeholderText.windows.wildcard; + return placeholderText().windows.wildcard; } - return placeholderText.windows.exact; + return placeholderText().windows.exact; } else { if (type === 'wildcard') { - return placeholderText.others.wildcard; + return placeholderText().others.wildcard; } - return placeholderText.others.exact; + return placeholderText().others.exact; } } }; From 4e7dce9e780637b5cfdb7ef40bff800a3074ea0a Mon Sep 17 00:00:00 2001 From: Ashokaditya Date: Thu, 29 Apr 2021 11:24:56 +0200 Subject: [PATCH 36/36] use semantic names for functions refs 330731ebfcfd356707b5ff38d60106e6f1e409d9 --- .../common/utils/path_placeholder.test.ts | 32 +++++++++---------- .../common/utils/path_placeholder.ts | 12 +++---- .../condition_entry_input/index.tsx | 4 +-- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/security_solution/common/utils/path_placeholder.test.ts b/x-pack/plugins/security_solution/common/utils/path_placeholder.test.ts index 50bf0d670a109..9618440c105dc 100644 --- a/x-pack/plugins/security_solution/common/utils/path_placeholder.test.ts +++ b/x-pack/plugins/security_solution/common/utils/path_placeholder.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { getPlaceholderText, placeholderText } from './path_placeholder'; +import { getPlaceholderTextByOSType, getPlaceholderText } from './path_placeholder'; import { ConditionEntryField, OperatingSystem, TrustedAppEntryTypes } from '../endpoint/types'; const trustedAppEntry = { @@ -16,54 +16,54 @@ const trustedAppEntry = { describe('Trusted Apps: Path placeholder text', () => { it('returns no placeholder text when field IS NOT PATH', () => { - expect(getPlaceholderText({ ...trustedAppEntry })).toEqual(undefined); + expect(getPlaceholderTextByOSType({ ...trustedAppEntry })).toEqual(undefined); }); it('returns a placeholder text when field IS PATH', () => { - expect(getPlaceholderText({ ...trustedAppEntry, field: ConditionEntryField.PATH })).toEqual( - placeholderText().others.exact - ); + expect( + getPlaceholderTextByOSType({ ...trustedAppEntry, field: ConditionEntryField.PATH }) + ).toEqual(getPlaceholderText().others.exact); }); - it('returns LINUX/MAC equivalent placholder when field IS PATH', () => { + it('returns LINUX/MAC equivalent placeholder when field IS PATH', () => { expect( - getPlaceholderText({ + getPlaceholderTextByOSType({ ...trustedAppEntry, os: OperatingSystem.MAC, field: ConditionEntryField.PATH, }) - ).toEqual(placeholderText().others.exact); + ).toEqual(getPlaceholderText().others.exact); }); - it('returns LINUX/MAC equivalent placholder text when field IS PATH and WILDCARD operator is selected', () => { + it('returns LINUX/MAC equivalent placeholder text when field IS PATH and WILDCARD operator is selected', () => { expect( - getPlaceholderText({ + getPlaceholderTextByOSType({ ...trustedAppEntry, os: OperatingSystem.LINUX, field: ConditionEntryField.PATH, type: 'wildcard', }) - ).toEqual(placeholderText().others.wildcard); + ).toEqual(getPlaceholderText().others.wildcard); }); - it('returns WINDOWS equivalent placholder text when field IS PATH', () => { + it('returns WINDOWS equivalent placeholder text when field IS PATH', () => { expect( - getPlaceholderText({ + getPlaceholderTextByOSType({ ...trustedAppEntry, os: OperatingSystem.WINDOWS, field: ConditionEntryField.PATH, }) - ).toEqual(placeholderText().windows.exact); + ).toEqual(getPlaceholderText().windows.exact); }); it('returns WINDOWS equivalent placeholder text when field IS PATH and WILDCARD operator is selected', () => { expect( - getPlaceholderText({ + getPlaceholderTextByOSType({ ...trustedAppEntry, os: OperatingSystem.WINDOWS, field: ConditionEntryField.PATH, type: 'wildcard', }) - ).toEqual(placeholderText().windows.wildcard); + ).toEqual(getPlaceholderText().windows.wildcard); }); }); diff --git a/x-pack/plugins/security_solution/common/utils/path_placeholder.ts b/x-pack/plugins/security_solution/common/utils/path_placeholder.ts index d87934b97908a..bba01b6d05b65 100644 --- a/x-pack/plugins/security_solution/common/utils/path_placeholder.ts +++ b/x-pack/plugins/security_solution/common/utils/path_placeholder.ts @@ -7,7 +7,7 @@ import { ConditionEntryField, OperatingSystem, TrustedAppEntryTypes } from '../endpoint/types'; -export const placeholderText = () => ({ +export const getPlaceholderText = () => ({ windows: { wildcard: 'C:\\sample\\**\\*', exact: 'C:\\sample\\path.exe', @@ -18,7 +18,7 @@ export const placeholderText = () => ({ }, }); -export const getPlaceholderText = ({ +export const getPlaceholderTextByOSType = ({ os, field, type, @@ -30,14 +30,14 @@ export const getPlaceholderText = ({ if (field === ConditionEntryField.PATH) { if (os === OperatingSystem.WINDOWS) { if (type === 'wildcard') { - return placeholderText().windows.wildcard; + return getPlaceholderText().windows.wildcard; } - return placeholderText().windows.exact; + return getPlaceholderText().windows.exact; } else { if (type === 'wildcard') { - return placeholderText().others.wildcard; + return getPlaceholderText().others.wildcard; } - return placeholderText().others.exact; + return getPlaceholderText().others.exact; } } }; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx index 7915e3ed30bae..d052138d309ac 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_entry_input/index.tsx @@ -31,7 +31,7 @@ import { OPERATOR_TITLES, } from '../../translations'; import { useTestIdGenerator } from '../../../../../components/hooks/use_test_id_generator'; -import { getPlaceholderText } from '../../../../../../../common/utils/path_placeholder'; +import { getPlaceholderTextByOSType } from '../../../../../../../common/utils/path_placeholder'; const ConditionEntryCell = memo<{ showLabel: boolean; @@ -193,7 +193,7 @@ export const ConditionEntryInput = memo(