[Security Solution][EDR Workflows] Remove the filter on Endpoint Exceptions and Event Filters creation to allow more user flexibility (#162193)

## Summary

This PR removes the predefined sets of Exceptions for Endpoint
Exceptions and Event Filters. This comes after user feedback that we are
too restrictive in which fields we allow users to write Exceptions or
Event Filters for. This will give users much more freedom in creating
Exceptions and Event Filters.

The `filterIndexPatterns()` function is entirely removed as Endpoint
Exceptions and Event Filters were the only features using it. Following
that, the props for many downstream components was updated to remove
reference to this filtering function.

Further, in working the the Endpoint and Protections teams, there are no
concerns with removing these filters from an Endpoint perspective and
the added flexibility for users is welcome.

User now has access to all the fields that we pull back from the index
mappings.

<img width="1728" alt="image"
src="8ccb6b33-e7e7-42d6-a9a9-68e65c3be57d">

<img width="1728" alt="image"
src="35f26431-07b2-4995-932c-6c5023ced7fd">

### Checklist

Delete any items that are not applicable to this PR.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Kevin Logan 2023-08-03 12:53:17 -04:00 committed by GitHub
parent 7e2ba48c18
commit 1a3aefe6ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 61 additions and 943 deletions

View file

@ -19,7 +19,6 @@ import {
NamespaceType, NamespaceType,
ListOperatorEnum as OperatorEnum, ListOperatorEnum as OperatorEnum,
ListOperatorTypeEnum as OperatorTypeEnum, ListOperatorTypeEnum as OperatorTypeEnum,
OsTypeArray,
createExceptionListItemSchema, createExceptionListItemSchema,
entriesList, entriesList,
entriesNested, entriesNested,
@ -302,18 +301,13 @@ export const getUpdatedEntriesOnDelete = (
*/ */
export const getFilteredIndexPatterns = ( export const getFilteredIndexPatterns = (
patterns: DataViewBase, patterns: DataViewBase,
item: FormattedBuilderEntry, item: FormattedBuilderEntry
type: ExceptionListType,
preFilter?: (i: DataViewBase, t: ExceptionListType, o?: OsTypeArray) => DataViewBase,
osTypes?: OsTypeArray
): DataViewBase => { ): DataViewBase => {
const indexPatterns = preFilter != null ? preFilter(patterns, type, osTypes) : patterns;
if (item.nested === 'child' && item.parent != null) { if (item.nested === 'child' && item.parent != null) {
// when user has selected a nested entry, only fields with the common parent are shown // when user has selected a nested entry, only fields with the common parent are shown
return { return {
...indexPatterns, ...patterns,
fields: indexPatterns.fields fields: patterns.fields
.filter((indexField) => { .filter((indexField) => {
const subTypeNested = getDataViewFieldSubtypeNested(indexField); const subTypeNested = getDataViewFieldSubtypeNested(indexField);
const fieldHasCommonParentPath = const fieldHasCommonParentPath =
@ -330,15 +324,15 @@ export const getFilteredIndexPatterns = (
}; };
} else if (item.nested === 'parent' && item.field != null) { } else if (item.nested === 'parent' && item.field != null) {
// when user has selected a nested entry, right above it we show the common parent // when user has selected a nested entry, right above it we show the common parent
return { ...indexPatterns, fields: [item.field] }; return { ...patterns, fields: [item.field] };
} else if (item.nested === 'parent' && item.field == null) { } else if (item.nested === 'parent' && item.field == null) {
// when user selects to add a nested entry, only nested fields are shown as options // when user selects to add a nested entry, only nested fields are shown as options
return { return {
...indexPatterns, ...patterns,
fields: indexPatterns.fields.filter((field) => isDataViewFieldSubtypeNested(field)), fields: patterns.fields.filter((field) => isDataViewFieldSubtypeNested(field)),
}; };
} else { } else {
return indexPatterns; return patterns;
} }
}; };

View file

@ -190,13 +190,6 @@ export default {
required: true, required: true,
}, },
}, },
listTypeSpecificIndexPatternFilter: {
description:
'`(pattern: DataViewBase, type: ExceptionListType) => DataViewBase` - callback invoked when index patterns filtered. Optional to be used if you would only like certain fields displayed.',
type: {
required: false,
},
},
onChange: { onChange: {
description: description:
'`(arg: OnChangeProps) => void` - callback invoked any time builder update to propagate changes up to parent.', '`(arg: OnChangeProps) => void` - callback invoked any time builder update to propagate changes up to parent.',

View file

@ -76,11 +76,6 @@ export interface EntryItemProps {
showLabel: boolean; showLabel: boolean;
osTypes?: OsTypeArray; osTypes?: OsTypeArray;
listType: ExceptionListType; listType: ExceptionListType;
listTypeSpecificIndexPatternFilter?: (
pattern: DataViewBase,
type: ExceptionListType,
osTypes?: OsTypeArray
) => DataViewBase;
onChange: (arg: BuilderEntry, i: number) => void; onChange: (arg: BuilderEntry, i: number) => void;
onlyShowListOperators?: boolean; onlyShowListOperators?: boolean;
setErrorsExist: (arg: EntryFieldError) => void; setErrorsExist: (arg: EntryFieldError) => void;
@ -99,7 +94,6 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
indexPattern, indexPattern,
osTypes, osTypes,
listType, listType,
listTypeSpecificIndexPatternFilter,
onChange, onChange,
onlyShowListOperators = false, onlyShowListOperators = false,
setErrorsExist, setErrorsExist,
@ -204,13 +198,7 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
const renderFieldInput = useCallback( const renderFieldInput = useCallback(
(isFirst: boolean): JSX.Element => { (isFirst: boolean): JSX.Element => {
const filteredIndexPatterns = getFilteredIndexPatterns( const filteredIndexPatterns = getFilteredIndexPatterns(indexPattern, entry);
indexPattern,
entry,
listType,
listTypeSpecificIndexPatternFilter,
osTypes
);
const comboBox = ( const comboBox = (
<FieldComponent <FieldComponent
placeholder={ placeholder={
@ -312,9 +300,6 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
[ [
indexPattern, indexPattern,
entry, entry,
listType,
listTypeSpecificIndexPatternFilter,
osTypes,
isDisabled, isDisabled,
handleFieldChange, handleFieldChange,
allowCustomOptions, allowCustomOptions,

View file

@ -53,11 +53,6 @@ interface BuilderExceptionListItemProps {
andLogicIncluded: boolean; andLogicIncluded: boolean;
isOnlyItem: boolean; isOnlyItem: boolean;
listType: ExceptionListType; listType: ExceptionListType;
listTypeSpecificIndexPatternFilter?: (
pattern: DataViewBase,
type: ExceptionListType,
osTypes?: OsTypeArray
) => DataViewBase;
onDeleteExceptionItem: (item: ExceptionsBuilderExceptionItem, index: number) => void; onDeleteExceptionItem: (item: ExceptionsBuilderExceptionItem, index: number) => void;
onChangeExceptionItem: (item: ExceptionsBuilderExceptionItem, index: number) => void; onChangeExceptionItem: (item: ExceptionsBuilderExceptionItem, index: number) => void;
setErrorsExist: (arg: EntryFieldError) => void; setErrorsExist: (arg: EntryFieldError) => void;
@ -80,7 +75,6 @@ export const BuilderExceptionListItemComponent = React.memo<BuilderExceptionList
indexPattern, indexPattern,
isOnlyItem, isOnlyItem,
listType, listType,
listTypeSpecificIndexPatternFilter,
andLogicIncluded, andLogicIncluded,
onDeleteExceptionItem, onDeleteExceptionItem,
onChangeExceptionItem, onChangeExceptionItem,
@ -152,7 +146,6 @@ export const BuilderExceptionListItemComponent = React.memo<BuilderExceptionList
httpService={httpService} httpService={httpService}
indexPattern={indexPattern} indexPattern={indexPattern}
listType={listType} listType={listType}
listTypeSpecificIndexPatternFilter={listTypeSpecificIndexPatternFilter}
onChange={handleEntryChange} onChange={handleEntryChange}
onlyShowListOperators={onlyShowListOperators} onlyShowListOperators={onlyShowListOperators}
setErrorsExist={setErrorsExist} setErrorsExist={setErrorsExist}

View file

@ -89,10 +89,6 @@ export interface ExceptionBuilderProps {
listId: string | undefined; listId: string | undefined;
listNamespaceType: NamespaceType | undefined; listNamespaceType: NamespaceType | undefined;
listType: ExceptionListType; listType: ExceptionListType;
listTypeSpecificIndexPatternFilter?: (
pattern: DataViewBase,
type: ExceptionListType
) => DataViewBase;
onChange: (arg: OnChangeProps) => void; onChange: (arg: OnChangeProps) => void;
ruleName?: string; ruleName?: string;
isDisabled?: boolean; isDisabled?: boolean;
@ -115,7 +111,6 @@ export const ExceptionBuilderComponent = ({
listId, listId,
listNamespaceType, listNamespaceType,
listType, listType,
listTypeSpecificIndexPatternFilter,
onChange, onChange,
ruleName, ruleName,
exceptionItemName, exceptionItemName,
@ -461,7 +456,6 @@ export const ExceptionBuilderComponent = ({
isOnlyItem={exceptions.length === 1} isOnlyItem={exceptions.length === 1}
key={getExceptionListItemId(exceptionListItem, index)} key={getExceptionListItemId(exceptionListItem, index)}
listType={listType} listType={listType}
listTypeSpecificIndexPatternFilter={listTypeSpecificIndexPatternFilter}
onChangeExceptionItem={handleExceptionItemChange} onChangeExceptionItem={handleExceptionItemChange}
onDeleteExceptionItem={handleDeleteExceptionItem} onDeleteExceptionItem={handleDeleteExceptionItem}
onlyShowListOperators={containsValueListEntry(exceptions)} onlyShowListOperators={containsValueListEntry(exceptions)}

View file

@ -11,7 +11,6 @@ import {
EntryMatch, EntryMatch,
EntryMatchAny, EntryMatchAny,
EntryNested, EntryNested,
ExceptionListType,
ListOperatorEnum as OperatorEnum, ListOperatorEnum as OperatorEnum,
ListOperatorTypeEnum as OperatorTypeEnum, ListOperatorTypeEnum as OperatorTypeEnum,
} from '@kbn/securitysolution-io-ts-list-types'; } from '@kbn/securitysolution-io-ts-list-types';
@ -168,24 +167,13 @@ const mockEndpointFields = [
export const getEndpointField = (name: string): DataViewFieldBase => export const getEndpointField = (name: string): DataViewFieldBase =>
mockEndpointFields.find((field) => field.name === name) as DataViewFieldBase; mockEndpointFields.find((field) => field.name === name) as DataViewFieldBase;
const filterIndexPatterns = (patterns: DataViewBase, type: ExceptionListType): DataViewBase => {
return type === 'endpoint'
? {
...patterns,
fields: patterns.fields.filter(({ name }) =>
['file.path.caseless', 'file.Ext.code_signature.status'].includes(name)
),
}
: patterns;
};
describe('Exception builder helpers', () => { describe('Exception builder helpers', () => {
describe('#getFilteredIndexPatterns', () => { describe('#getFilteredIndexPatterns', () => {
describe('list type detections', () => { describe('list type detections', () => {
test('it returns nested fields that match parent value when "item.nested" is "child"', () => { test('it returns nested fields that match parent value when "item.nested" is "child"', () => {
const payloadIndexPattern = getMockIndexPattern(); const payloadIndexPattern = getMockIndexPattern();
const payloadItem: FormattedBuilderEntry = getMockNestedBuilderEntry(); const payloadItem: FormattedBuilderEntry = getMockNestedBuilderEntry();
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem, 'detection'); const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
const expected: DataViewBase = { const expected: DataViewBase = {
fields: [{ ...getField('nestedField.child'), name: 'child' }], fields: [{ ...getField('nestedField.child'), name: 'child' }],
id: '1234', id: '1234',
@ -197,7 +185,7 @@ describe('Exception builder helpers', () => {
test('it returns only parent nested field when "item.nested" is "parent" and nested parent field is not undefined', () => { test('it returns only parent nested field when "item.nested" is "parent" and nested parent field is not undefined', () => {
const payloadIndexPattern = getMockIndexPattern(); const payloadIndexPattern = getMockIndexPattern();
const payloadItem: FormattedBuilderEntry = getMockNestedParentBuilderEntry(); const payloadItem: FormattedBuilderEntry = getMockNestedParentBuilderEntry();
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem, 'detection'); const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
const expected: DataViewBase & { fields: Array<Partial<FieldSpec>> } = { const expected: DataViewBase & { fields: Array<Partial<FieldSpec>> } = {
fields: [{ ...getField('nestedField.child'), esTypes: ['nested'], name: 'nestedField' }], fields: [{ ...getField('nestedField.child'), esTypes: ['nested'], name: 'nestedField' }],
id: '1234', id: '1234',
@ -212,7 +200,7 @@ describe('Exception builder helpers', () => {
...getMockNestedParentBuilderEntry(), ...getMockNestedParentBuilderEntry(),
field: undefined, field: undefined,
}; };
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem, 'detection'); const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
const expected: DataViewBase = { const expected: DataViewBase = {
fields: [ fields: [
{ ...getField('nestedField.child') }, { ...getField('nestedField.child') },
@ -227,7 +215,7 @@ describe('Exception builder helpers', () => {
test('it returns all fields unfiletered if "item.nested" is not "child" or "parent"', () => { test('it returns all fields unfiletered if "item.nested" is not "child" or "parent"', () => {
const payloadIndexPattern = getMockIndexPattern(); const payloadIndexPattern = getMockIndexPattern();
const payloadItem: FormattedBuilderEntry = getMockBuilderEntry(); const payloadItem: FormattedBuilderEntry = getMockBuilderEntry();
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem, 'detection'); const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
const expected: DataViewBase = { const expected: DataViewBase = {
fields: [...fields], fields: [...fields],
id: '1234', id: '1234',
@ -265,7 +253,7 @@ describe('Exception builder helpers', () => {
}, },
value: 'some value', value: 'some value',
}; };
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem, 'endpoint'); const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
const expected: DataViewBase = { const expected: DataViewBase = {
fields: [{ ...getEndpointField('file.Ext.code_signature.status'), name: 'status' }], fields: [{ ...getEndpointField('file.Ext.code_signature.status'), name: 'status' }],
id: '1234', id: '1234',
@ -284,7 +272,7 @@ describe('Exception builder helpers', () => {
...getMockNestedParentBuilderEntry(), ...getMockNestedParentBuilderEntry(),
field, field,
}; };
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem, 'endpoint'); const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
const fieldsExpected: FieldSpec[] = [ const fieldsExpected: FieldSpec[] = [
{ {
aggregatable: false, aggregatable: false,
@ -315,53 +303,13 @@ describe('Exception builder helpers', () => {
...getMockNestedParentBuilderEntry(), ...getMockNestedParentBuilderEntry(),
field: undefined, field: undefined,
}; };
const output = getFilteredIndexPatterns( const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
payloadIndexPattern,
payloadItem,
'endpoint',
filterIndexPatterns
);
const expected: DataViewBase = { const expected: DataViewBase = {
fields: [getEndpointField('file.Ext.code_signature.status')], fields: [
id: '1234', { ...getField('nestedField.child') },
title: 'logstash-*', { ...getField('nestedField.nestedChild.doublyNestedChild') },
}; getEndpointField('file.Ext.code_signature.status'),
expect(output).toEqual(expected); ],
});
test('it returns all fields that matched those in "exceptionable_fields.json" with no further filtering if "item.nested" is not "child" or "parent"', () => {
const payloadItem: FormattedBuilderEntry = getMockBuilderEntry();
const output = getFilteredIndexPatterns(
payloadIndexPattern,
payloadItem,
'endpoint',
filterIndexPatterns
);
const fieldsExpected: FieldSpec[] = [
{
aggregatable: false,
count: 0,
esTypes: ['keyword'],
name: 'file.path.caseless',
readFromDocValues: false,
scripted: false,
searchable: true,
type: 'string',
},
{
aggregatable: false,
count: 0,
esTypes: ['text'],
name: 'file.Ext.code_signature.status',
readFromDocValues: false,
scripted: false,
searchable: true,
subType: { nested: { path: 'file.Ext.code_signature' } },
type: 'string',
},
];
const expected: DataViewBase = {
fields: fieldsExpected,
id: '1234', id: '1234',
title: 'logstash-*', title: 'logstash-*',
}; };

View file

@ -1,394 +0,0 @@
/*
* 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.
*/
export const EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS = [
'@timestamp',
'Endpoint.policy',
'Endpoint.policy.applied',
'Endpoint.policy.applied.id',
'Endpoint.policy.applied.name',
'Endpoint.policy.applied.status',
'Endpoint.status',
'agent.id',
'agent.name',
'agent.type',
'agent.version',
'cloud.account.id',
'cloud.instance.name',
'cloud.project.id',
'cloud.provider',
'cloud.region',
'container.id',
'container.image.hash.all',
'container.image.name',
'container.image.tag',
'container.name',
'data_stream.dataset',
'data_stream.namespace',
'data_stream.type',
'destination.address',
'destination.bytes',
'destination.domain',
'destination.geo.city_name',
'destination.geo.continent_name',
'destination.geo.country_iso_code',
'destination.geo.country_name',
'destination.geo.location',
'destination.geo.name',
'destination.geo.region_iso_code',
'destination.geo.region_name',
'destination.ip',
'destination.packets',
'destination.port',
'destination.registered_domain',
'destination.top_level_domain',
'dll.Ext',
'dll.Ext.code_signature',
'dll.Ext.code_signature.exists',
'dll.Ext.code_signature.status',
'dll.Ext.code_signature.subject_name',
'dll.Ext.code_signature.trusted',
'dll.Ext.code_signature.valid',
'dll.Ext.load_index',
'dll.code_signature.exists',
'dll.code_signature.status',
'dll.code_signature.subject_name',
'dll.code_signature.trusted',
'dll.code_signature.valid',
'dll.hash.md5',
'dll.hash.sha1',
'dll.hash.sha256',
'dll.hash.sha512',
'dll.name',
'dll.path',
'dll.pe.company',
'dll.pe.description',
'dll.pe.file_version',
'dll.pe.imphash',
'dll.pe.original_file_name',
'dll.pe.product',
'dns.Ext',
'dns.Ext.options',
'dns.Ext.status',
'dns.question.name',
'dns.question.registered_domain',
'dns.question.subdomain',
'dns.question.top_level_domain',
'dns.question.type',
'dns.resolved_ip',
'ecs.version',
'elastic.agent',
'elastic.agent.id',
'event.Ext',
'event.Ext.correlation',
'event.Ext.correlation.id',
'event.action',
'event.category',
'event.code',
'event.created',
'event.dataset',
'event.hash',
'event.id',
'event.ingested',
'event.module',
'event.outcome',
'event.provider',
'event.sequence',
'event.severity',
'event.type',
'file.Ext',
'file.Ext.code_signature',
'file.Ext.code_signature.exists',
'file.Ext.code_signature.status',
'file.Ext.code_signature.subject_name',
'file.Ext.code_signature.trusted',
'file.Ext.code_signature.valid',
'file.Ext.entropy',
'file.Ext.header_data',
'file.Ext.monotonic_id',
'file.Ext.original',
'file.Ext.original.gid',
'file.Ext.original.group',
'file.Ext.original.mode',
'file.Ext.original.name',
'file.Ext.original.owner',
'file.Ext.original.path',
'file.Ext.original.uid',
'file.Ext.windows',
'file.Ext.windows.zone_identifier',
'file.accessed',
'file.attributes',
'file.created',
'file.ctime',
'file.device',
'file.directory',
'file.drive_letter',
'file.extension',
'file.gid',
'file.group',
'file.hash.md5',
'file.hash.sha1',
'file.hash.sha256',
'file.hash.sha512',
'file.inode',
'file.mime_type',
'file.mode',
'file.mtime',
'file.name',
'file.owner',
'file.path',
'file.path.caseless',
'file.path.text',
'file.pe.company',
'file.pe.description',
'file.pe.file_version',
'file.pe.imphash',
'file.pe.original_file_name',
'file.pe.product',
'file.size',
'file.target_path',
'file.target_path.caseless',
'file.target_path.text',
'file.type',
'file.uid',
'group.Ext',
'group.Ext.real',
'group.Ext.real.id',
'group.Ext.real.name',
'group.domain',
'group.id',
'group.name',
'host.architecture',
'host.domain',
'host.hostname',
'host.id',
'host.ip',
'host.mac',
'host.name',
'host.os.Ext',
'host.os.Ext.variant',
'host.os.family',
'host.os.full',
'host.os.full.caseless',
'host.os.full.text',
'host.os.kernel',
'host.os.name',
'host.os.name.caseless',
'host.os.name.text',
'host.os.platform',
'host.os.version',
'host.type',
'host.uptime',
'http.request.body.bytes',
'http.request.body.content',
'http.request.body.content.text',
'http.request.bytes',
'http.response.Ext',
'http.response.Ext.version',
'http.response.body.bytes',
'http.response.body.content',
'http.response.body.content.text',
'http.response.bytes',
'http.response.status_code',
'message',
'network.bytes',
'network.community_id',
'network.direction',
'network.iana_number',
'network.packets',
'network.protocol',
'network.transport',
'network.type',
'orchestrator.cluster.id',
'orchestrator.cluster.name',
'orchestrator.resource.ip',
'orchestrator.resource.name',
'orchestrator.resource.parent.type',
'orchestrator.resource.type',
'package.name',
'process.Ext',
'process.Ext.ancestry',
'process.Ext.authentication_id',
'process.Ext.code_signature',
'process.Ext.code_signature.exists',
'process.Ext.code_signature.status',
'process.Ext.code_signature.subject_name',
'process.Ext.code_signature.trusted',
'process.Ext.code_signature.valid',
'process.Ext.defense_evasions',
'process.Ext.session',
'process.Ext.token.elevation',
'process.Ext.token.elevation_type',
'process.Ext.token.integrity_level_name',
'process.args',
'process.args_count',
'process.code_signature.exists',
'process.code_signature.status',
'process.code_signature.subject_name',
'process.code_signature.trusted',
'process.code_signature.valid',
'process.command_line',
'process.command_line.caseless',
'process.command_line.text',
'process.entity_id',
'process.entry_leader.command_line',
'process.entry_leader.entry_meta.source.ip',
'process.entry_leader.entry_meta.type',
'process.entry_leader.executable',
'process.entry_leader.group.id',
'process.entry_leader.group.name',
'process.entry_leader.interactive',
'process.entry_leader.name',
'process.entry_leader.user.id',
'process.entry_leader.user.name',
'process.entry_leader.working_directory',
'process.executable',
'process.executable.caseless',
'process.executable.text',
'process.exit_code',
'process.group_leader.args',
'process.group_leader.command_line',
'process.group_leader.executable',
'process.group_leader.group.id',
'process.group_leader.group.name',
'process.group_leader.interactive',
'process.group_leader.name',
'process.group_leader.user.id',
'process.group_leader.user.name',
'process.group_leader.working_directory',
'process.hash.md5',
'process.hash.sha1',
'process.hash.sha256',
'process.hash.sha512',
'process.interactive',
'process.io.text',
'process.name',
'process.name.caseless',
'process.name.text',
'process.parent.Ext',
'process.parent.Ext.code_signature',
'process.parent.Ext.code_signature.exists',
'process.parent.Ext.code_signature.status',
'process.parent.Ext.code_signature.subject_name',
'process.parent.Ext.code_signature.trusted',
'process.parent.Ext.code_signature.valid',
'process.parent.Ext.real',
'process.parent.Ext.real.pid',
'process.parent.args',
'process.parent.args_count',
'process.parent.code_signature.exists',
'process.parent.code_signature.status',
'process.parent.code_signature.subject_name',
'process.parent.code_signature.trusted',
'process.parent.code_signature.valid',
'process.parent.command_line',
'process.parent.command_line.caseless',
'process.parent.command_line.text',
'process.parent.entity_id',
'process.parent.executable',
'process.parent.executable.caseless',
'process.parent.executable.text',
'process.parent.exit_code',
'process.parent.group.id',
'process.parent.group.name',
'process.parent.hash.md5',
'process.parent.hash.sha1',
'process.parent.hash.sha256',
'process.parent.hash.sha512',
'process.parent.interactive',
'process.parent.name',
'process.parent.name.caseless',
'process.parent.name.text',
'process.parent.pe.company',
'process.parent.pe.description',
'process.parent.pe.file_version',
'process.parent.pe.imphash',
'process.parent.pe.original_file_name',
'process.parent.pe.product',
'process.parent.pgid',
'process.parent.pid',
'process.parent.ppid',
'process.parent.thread.id',
'process.parent.thread.name',
'process.parent.title',
'process.parent.title.text',
'process.parent.uptime',
'process.parent.user.id',
'process.parent.user.name',
'process.parent.working_directory',
'process.parent.working_directory',
'process.parent.working_directory.caseless',
'process.parent.working_directory.text',
'process.pe.company',
'process.pe.description',
'process.pe.file_version',
'process.pe.imphash',
'process.pe.original_file_name',
'process.pe.product',
'process.pgid',
'process.pid',
'process.ppid',
'process.session_leader.args',
'process.session_leader.command_line',
'process.session_leader.executable',
'process.session_leader.group.id',
'process.session_leader.group.name',
'process.session_leader.interactive',
'process.session_leader.name',
'process.session_leader.user.id',
'process.session_leader.user.name',
'process.session_leader.working_directory',
'process.thread.id',
'process.thread.name',
'process.title',
'process.title.text',
'process.uptime',
'process.working_directory',
'process.working_directory.caseless',
'process.working_directory.text',
'registry.data.bytes',
'registry.data.strings',
'registry.hive',
'registry.key',
'registry.path',
'registry.value',
'source.address',
'source.bytes',
'source.domain',
'source.geo.city_name',
'source.geo.continent_name',
'source.geo.country_iso_code',
'source.geo.country_name',
'source.geo.location',
'source.geo.name',
'source.geo.region_iso_code',
'source.geo.region_name',
'source.ip',
'source.packets',
'source.port',
'source.registered_domain',
'source.top_level_domain',
'user.Ext',
'user.Ext.real',
'user.Ext.real.id',
'user.Ext.real.name',
'user.domain',
'user.email',
'user.full_name',
'user.full_name.text',
'user.group.Ext',
'user.group.Ext.real',
'user.group.Ext.real.id',
'user.group.Ext.real.name',
'user.group.domain',
'user.group.id',
'user.group.name',
'user.hash',
'user.id',
'user.name',
'user.name.text',
];

View file

@ -23,7 +23,7 @@ import {
} from '../../../tasks/create_new_rule'; } from '../../../tasks/create_new_rule';
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation';
import { import {
addExceptionEntryFieldValue, addExceptionEntryFieldValueAndSelectSuggestion,
addExceptionEntryFieldValueValue, addExceptionEntryFieldValueValue,
addExceptionFlyoutItemName, addExceptionFlyoutItemName,
editExceptionFlyoutItemName, editExceptionFlyoutItemName,
@ -98,7 +98,7 @@ describe('Endpoint Exceptions workflows from Alert', () => {
cy.get(ADD_AND_BTN).click(); cy.get(ADD_AND_BTN).click();
// edit conditions // edit conditions
addExceptionEntryFieldValue(ADDITIONAL_ENTRY, 6); addExceptionEntryFieldValueAndSelectSuggestion(ADDITIONAL_ENTRY, 6);
addExceptionEntryFieldValueValue('foo', 4); addExceptionEntryFieldValueValue('foo', 4);
// Change the name again // Change the name again

View file

@ -99,6 +99,11 @@ export const addExceptionEntryFieldValue = (field: string, index = 0) => {
cy.get(EXCEPTION_FLYOUT_TITLE).click(); cy.get(EXCEPTION_FLYOUT_TITLE).click();
}; };
export const addExceptionEntryFieldValueAndSelectSuggestion = (field: string, index = 0) => {
cy.get(FIELD_INPUT).eq(index).type(`${field}`);
cy.get(`button[title="${field}"]`).click();
};
export const addExceptionEntryOperatorValue = (operator: string, index = 0) => { export const addExceptionEntryOperatorValue = (operator: string, index = 0) => {
cy.get(OPERATOR_INPUT).eq(index).type(`${operator}{enter}`); cy.get(OPERATOR_INPUT).eq(index).type(`${operator}{enter}`);
cy.get(EXCEPTION_FLYOUT_TITLE).click(); cy.get(EXCEPTION_FLYOUT_TITLE).click();

View file

@ -40,7 +40,6 @@ import { ExceptionItemComments } from '../item_comments';
import { import {
defaultEndpointExceptionItems, defaultEndpointExceptionItems,
retrieveAlertOsTypes, retrieveAlertOsTypes,
filterIndexPatterns,
getPrepopulatedRuleExceptionWithHighlightFields, getPrepopulatedRuleExceptionWithHighlightFields,
} from '../../utils/helpers'; } from '../../utils/helpers';
import type { AlertData } from '../../utils/types'; import type { AlertData } from '../../utils/types';
@ -515,7 +514,6 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({
onOsChange={setSelectedOs} onOsChange={setSelectedOs}
onExceptionItemAdd={setExceptionItemsToAdd} onExceptionItemAdd={setExceptionItemsToAdd}
onSetErrorExists={setConditionsValidationError} onSetErrorExists={setConditionsValidationError}
onFilterIndexPatterns={filterIndexPatterns}
getExtendedFields={getExtendedFields} getExtendedFields={getExtendedFields}
/> />

View file

@ -48,7 +48,6 @@ import { ExceptionsLinkedToRule } from '../flyout_components/linked_to_rule';
import { ExceptionItemsFlyoutAlertsActions } from '../flyout_components/alerts_actions'; import { ExceptionItemsFlyoutAlertsActions } from '../flyout_components/alerts_actions';
import { ExceptionsConditions } from '../flyout_components/item_conditions'; import { ExceptionsConditions } from '../flyout_components/item_conditions';
import { filterIndexPatterns } from '../../utils/helpers';
import { useFetchIndexPatterns } from '../../logic/use_exception_flyout_data'; import { useFetchIndexPatterns } from '../../logic/use_exception_flyout_data';
import { useCloseAlertsFromExceptions } from '../../logic/use_close_alerts'; import { useCloseAlertsFromExceptions } from '../../logic/use_close_alerts';
import { useFindExceptionListReferences } from '../../logic/use_find_references'; import { useFindExceptionListReferences } from '../../logic/use_find_references';
@ -369,7 +368,6 @@ const EditExceptionFlyoutComponent: React.FC<EditExceptionFlyoutProps> = ({
isEdit isEdit
onExceptionItemAdd={setExceptionItemsToAdd} onExceptionItemAdd={setExceptionItemsToAdd}
onSetErrorExists={setConditionsValidationError} onSetErrorExists={setConditionsValidationError}
onFilterIndexPatterns={filterIndexPatterns}
getExtendedFields={getExtendedFields} getExtendedFields={getExtendedFields}
/> />
{!openedFromListDetailPage && listType === ExceptionListTypeEnum.DETECTION && ( {!openedFromListDetailPage && listType === ExceptionListTypeEnum.DETECTION && (

View file

@ -41,7 +41,6 @@ describe('ExceptionsConditions', () => {
onOsChange={jest.fn()} onOsChange={jest.fn()}
onExceptionItemAdd={jest.fn()} onExceptionItemAdd={jest.fn()}
onSetErrorExists={jest.fn()} onSetErrorExists={jest.fn()}
onFilterIndexPatterns={jest.fn()}
/> />
</TestProviders> </TestProviders>
); );
@ -72,7 +71,6 @@ describe('ExceptionsConditions', () => {
onOsChange={jest.fn()} onOsChange={jest.fn()}
onExceptionItemAdd={jest.fn()} onExceptionItemAdd={jest.fn()}
onSetErrorExists={jest.fn()} onSetErrorExists={jest.fn()}
onFilterIndexPatterns={jest.fn()}
/> />
</TestProviders> </TestProviders>
); );
@ -102,7 +100,6 @@ describe('ExceptionsConditions', () => {
onOsChange={jest.fn()} onOsChange={jest.fn()}
onExceptionItemAdd={jest.fn()} onExceptionItemAdd={jest.fn()}
onSetErrorExists={jest.fn()} onSetErrorExists={jest.fn()}
onFilterIndexPatterns={jest.fn()}
/> />
</TestProviders> </TestProviders>
); );
@ -132,7 +129,6 @@ describe('ExceptionsConditions', () => {
onOsChange={jest.fn()} onOsChange={jest.fn()}
onExceptionItemAdd={jest.fn()} onExceptionItemAdd={jest.fn()}
onSetErrorExists={jest.fn()} onSetErrorExists={jest.fn()}
onFilterIndexPatterns={jest.fn()}
/> />
</TestProviders> </TestProviders>
); );
@ -165,7 +161,6 @@ describe('ExceptionsConditions', () => {
onOsChange={jest.fn()} onOsChange={jest.fn()}
onExceptionItemAdd={jest.fn()} onExceptionItemAdd={jest.fn()}
onSetErrorExists={jest.fn()} onSetErrorExists={jest.fn()}
onFilterIndexPatterns={jest.fn()}
/> />
</TestProviders> </TestProviders>
); );
@ -196,7 +191,6 @@ describe('ExceptionsConditions', () => {
onOsChange={jest.fn()} onOsChange={jest.fn()}
onExceptionItemAdd={jest.fn()} onExceptionItemAdd={jest.fn()}
onSetErrorExists={jest.fn()} onSetErrorExists={jest.fn()}
onFilterIndexPatterns={jest.fn()}
/> />
</TestProviders> </TestProviders>
); );

View file

@ -85,11 +85,6 @@ interface ExceptionsFlyoutConditionsComponentProps {
onExceptionItemAdd: (items: ExceptionsBuilderReturnExceptionItem[]) => void; onExceptionItemAdd: (items: ExceptionsBuilderReturnExceptionItem[]) => void;
/* Exception item builder takes a callback used when there are updates to the item that includes information on if any form errors exist */ /* Exception item builder takes a callback used when there are updates to the item that includes information on if any form errors exist */
onSetErrorExists: (errorExists: boolean) => void; onSetErrorExists: (errorExists: boolean) => void;
onFilterIndexPatterns: (
patterns: DataViewBase,
type: ExceptionListType,
osTypes?: Array<'linux' | 'macos' | 'windows'> | undefined
) => DataViewBase;
getExtendedFields?: (fields: string[]) => Promise<DataViewField[]>; getExtendedFields?: (fields: string[]) => Promise<DataViewField[]>;
} }
@ -107,7 +102,6 @@ const ExceptionsConditionsComponent: React.FC<ExceptionsFlyoutConditionsComponen
onOsChange, onOsChange,
onExceptionItemAdd, onExceptionItemAdd,
onSetErrorExists, onSetErrorExists,
onFilterIndexPatterns,
getExtendedFields, getExtendedFields,
}): JSX.Element => { }): JSX.Element => {
const { http, unifiedSearch } = useKibana().services; const { http, unifiedSearch } = useKibana().services;
@ -260,7 +254,6 @@ const ExceptionsConditionsComponent: React.FC<ExceptionsFlyoutConditionsComponen
osTypes, osTypes,
listId: listIdToUse, listId: listIdToUse,
listNamespaceType, listNamespaceType,
listTypeSpecificIndexPatternFilter: onFilterIndexPatterns,
exceptionItemName, exceptionItemName,
indexPatterns, indexPatterns,
isOrDisabled: isExceptionBuilderFormDisabled, isOrDisabled: isExceptionBuilderFormDisabled,

View file

@ -1,150 +0,0 @@
[
"Endpoint.policy.applied.id",
"Target.process.Ext.services",
"Target.process.Ext.user",
"Target.process.executable",
"Target.process.hash.md5",
"Target.process.hash.sha1",
"Target.process.hash.sha256",
"Target.process.hash.sha512",
"Target.process.name",
"Target.process.parent.hash.md5",
"Target.process.parent.hash.sha1",
"Target.process.parent.hash.sha256",
"Target.process.parent.hash.sha512",
"Target.process.parent.pgid",
"Target.process.pe.company",
"Target.process.pe.description",
"Target.process.pe.file_version",
"Target.process.pe.original_file_name",
"Target.process.pe.product",
"Target.process.pgid",
"Target.process.Ext.memory_region.allocation_type",
"Target.process.thread.Ext.start_address_bytes_disasm_hash",
"Target.process.thread.Ext.start_address_allocation_offset",
"Target.process.Ext.memory_region.allocation_size",
"Target.process.Ext.memory_region.region_size",
"Target.process.Ext.memory_region.region_protection",
"Target.process.Ext.memory_region.memory_pe.imphash",
"Target.process.thread.Ext.start_address_bytes",
"agent.id",
"agent.type",
"agent.version",
"Effective_process.entity_id",
"Effective_process.executable",
"Effective_process.name",
"Effective_process.pid",
"elastic.agent.id",
"event.action",
"event.category",
"event.code",
"event.hash",
"event.kind",
"event.module",
"event.outcome",
"event.provider",
"event.type",
"file.attributes",
"file.device",
"file.directory",
"file.drive_letter",
"file.extension",
"file.gid",
"file.group",
"file.hash.md5",
"file.hash.sha1",
"file.hash.sha256",
"file.hash.sha512",
"file.inode",
"file.mime_type",
"file.mode",
"file.name",
"file.owner",
"file.path",
"file.pe.company",
"file.pe.description",
"file.pe.Ext.dotnet",
"file.pe.Ext.streams.hash.md5",
"file.pe.Ext.streams.hash.sha256",
"file.pe.Ext.streams.name",
"file.pe.Ext.sections.hash.md5",
"file.pe.Ext.sections.hash.sha256",
"file.pe.file_version",
"file.pe.original_file_name",
"file.pe.product",
"file.size",
"file.type",
"file.uid",
"group.Ext.real.id",
"group.domain",
"group.id",
"host.architecture",
"host.domain",
"host.hostname",
"host.id",
"host.name",
"host.os.Ext.variant",
"host.os.family",
"host.os.kernel",
"host.os.platform",
"host.os.version",
"host.type",
"process.args",
"process.command_line",
"process.code_signature.subject_name",
"process.Ext.services",
"process.Ext.user",
"process.Ext.code_signature",
"process.Ext.token.integrity_level_name",
"process.Ext.memory_region.malware_signature.all_names",
"process.executable",
"process.hash.md5",
"process.hash.sha1",
"process.hash.sha256",
"process.hash.sha512",
"process.name",
"process.parent.args",
"process.parent.executable",
"process.parent.hash.md5",
"process.parent.hash.sha1",
"process.parent.hash.sha256",
"process.parent.hash.sha512",
"process.parent.pgid",
"process.pe.company",
"process.pe.description",
"process.pe.file_version",
"process.pe.original_file_name",
"process.pe.product",
"process.pgid",
"rule.uuid",
"rule.id",
"source.ip",
"source.port",
"destination.ip",
"destination.port",
"registry.path",
"registry.value",
"registry.data.strings",
"user.domain",
"user.email",
"user.hash",
"user.id",
"Ransomware.feature",
"Ransomware.files.data",
"Ransomware.files.entropy",
"Ransomware.files.extension",
"Ransomware.files.operation",
"Ransomware.files.path",
"Ransomware.child_processes.files.data",
"Ransomware.child_processes.files.entropy",
"Ransomware.child_processes.files.extension",
"Ransomware.child_processes.files.operation",
"Ransomware.child_processes.files.path",
"Memory_protection.feature",
"Memory_protection.self_injection",
"dll.path",
"dll.code_signature.subject_name",
"dll.pe.original_file_name",
"dns.question.name",
"dns.question.type"
]

View file

@ -1,22 +0,0 @@
[
"file.path",
"file.target_path",
"Target.process.command_line",
"Target.process.executable",
"Target.process.name",
"Target.process.parent.command_line",
"Target.process.parent.executable",
"Target.process.parent.name",
"Target.process.parent.working_directory",
"Target.process.working_directory",
"host.os.full",
"host.os.name",
"process.command_line",
"process.executable",
"process.name",
"process.parent.command_line",
"process.parent.executable",
"process.parent.name",
"process.parent.working_directory",
"process.working_directory"
]

View file

@ -1,38 +0,0 @@
[
"file.path.caseless",
"file.target_path.caseless",
"Target.process.command_line.caseless",
"Target.process.executable.caseless",
"Target.process.name.caseless",
"Target.process.parent.command_line.caseless",
"Target.process.parent.executable.caseless",
"Target.process.parent.name.caseless",
"Target.process.parent.working_directory.caseless",
"Target.process.working_directory.caseless",
"host.os.full.caseless",
"host.os.name.caseless",
"process.command_line.caseless",
"process.executable.caseless",
"process.name.caseless",
"process.parent.command_line.caseless",
"process.parent.executable.caseless",
"process.parent.name.caseless",
"process.parent.working_directory.caseless",
"process.working_directory.caseless",
"Target.process.Ext.code_signature.status",
"Target.process.Ext.code_signature.subject_name",
"Target.process.Ext.code_signature.trusted",
"Target.process.Ext.code_signature.valid",
"Target.process.parent.Ext.code_signature.status",
"Target.process.parent.Ext.code_signature.subject_name",
"Target.process.parent.Ext.code_signature.trusted",
"Target.process.parent.Ext.code_signature.valid",
"file.Ext.code_signature.status",
"file.Ext.code_signature.subject_name",
"file.Ext.code_signature.trusted",
"file.Ext.code_signature.valid",
"process.parent.Ext.code_signature.status",
"process.parent.Ext.code_signature.subject_name",
"process.parent.Ext.code_signature.trusted",
"process.parent.Ext.code_signature.valid"
]

View file

@ -23,7 +23,6 @@ import {
getFileCodeSignature, getFileCodeSignature,
getProcessCodeSignature, getProcessCodeSignature,
retrieveAlertOsTypes, retrieveAlertOsTypes,
filterIndexPatterns,
getCodeSignatureValue, getCodeSignatureValue,
buildRuleExceptionWithConditions, buildRuleExceptionWithConditions,
buildExceptionEntriesFromAlertFields, buildExceptionEntriesFromAlertFields,
@ -39,12 +38,10 @@ import type {
ExceptionListItemSchema, ExceptionListItemSchema,
} from '@kbn/securitysolution-io-ts-list-types'; } from '@kbn/securitysolution-io-ts-list-types';
import { ListOperatorTypeEnum, ListOperatorEnum } from '@kbn/securitysolution-io-ts-list-types'; import { ListOperatorTypeEnum, ListOperatorEnum } from '@kbn/securitysolution-io-ts-list-types';
import type { DataViewBase } from '@kbn/es-query';
import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock';
import { getEntryMatchMock } from '@kbn/lists-plugin/common/schemas/types/entry_match.mock'; import { getEntryMatchMock } from '@kbn/lists-plugin/common/schemas/types/entry_match.mock';
import { getCommentsArrayMock } from '@kbn/lists-plugin/common/schemas/types/comment.mock'; import { getCommentsArrayMock } from '@kbn/lists-plugin/common/schemas/types/comment.mock';
import { fields } from '@kbn/data-plugin/common/mocks';
import { ENTRIES, OLD_DATE_RELATIVE_TO_DATE_NOW } from '@kbn/lists-plugin/common/constants.mock'; import { ENTRIES, OLD_DATE_RELATIVE_TO_DATE_NOW } from '@kbn/lists-plugin/common/constants.mock';
import type { CodeSignature } from '@kbn/securitysolution-ecs'; import type { CodeSignature } from '@kbn/securitysolution-ecs';
import { import {
@ -56,49 +53,6 @@ jest.mock('uuid', () => ({
v4: jest.fn().mockReturnValue('123'), v4: jest.fn().mockReturnValue('123'),
})); }));
const getMockIndexPattern = (): DataViewBase => ({
fields,
id: '1234',
title: 'logstash-*',
});
const mockEndpointFields = [
{
name: 'file.path.caseless',
type: 'string',
esTypes: ['keyword'],
count: 0,
scripted: false,
searchable: true,
aggregatable: false,
readFromDocValues: false,
},
{
name: 'file.Ext.code_signature.status',
type: 'string',
esTypes: ['text'],
count: 0,
scripted: false,
searchable: true,
aggregatable: false,
readFromDocValues: false,
subType: { nested: { path: 'file.Ext.code_signature' } },
},
];
const mockLinuxEndpointFields = [
{
name: 'file.path',
type: 'string',
esTypes: ['keyword'],
count: 0,
scripted: false,
searchable: true,
aggregatable: false,
readFromDocValues: false,
},
];
describe('Exception helpers', () => { describe('Exception helpers', () => {
beforeEach(() => { beforeEach(() => {
moment.tz.setDefault('UTC'); moment.tz.setDefault('UTC');
@ -108,35 +62,6 @@ describe('Exception helpers', () => {
moment.tz.setDefault('Browser'); moment.tz.setDefault('Browser');
}); });
describe('#filterIndexPatterns', () => {
test('it returns index patterns without filtering if list type is "detection"', () => {
const mockIndexPatterns = getMockIndexPattern();
const output = filterIndexPatterns(mockIndexPatterns, 'detection', ['windows']);
expect(output).toEqual(mockIndexPatterns);
});
test('it returns filtered index patterns if list type is "endpoint"', () => {
const mockIndexPatterns = {
...getMockIndexPattern(),
fields: [...fields, ...mockEndpointFields],
};
const output = filterIndexPatterns(mockIndexPatterns, 'endpoint', ['windows']);
expect(output).toEqual({ ...getMockIndexPattern(), fields: [...mockEndpointFields] });
});
test('it returns filtered index patterns if list type is "endpoint" and os contains "linux"', () => {
const mockIndexPatterns = {
...getMockIndexPattern(),
fields: [...fields, ...mockLinuxEndpointFields],
};
const output = filterIndexPatterns(mockIndexPatterns, 'endpoint', ['linux']);
expect(output).toEqual({ ...getMockIndexPattern(), fields: [...mockLinuxEndpointFields] });
});
});
describe('#formatOperatingSystems', () => { describe('#formatOperatingSystems', () => {
test('it returns null if no operating system tag specified', () => { test('it returns null if no operating system tag specified', () => {
const result = formatOperatingSystems(['some os', 'some other os']); const result = formatOperatingSystems(['some os', 'some other os']);

View file

@ -20,7 +20,6 @@ import type {
NamespaceType, NamespaceType,
EntryNested, EntryNested,
OsTypeArray, OsTypeArray,
ExceptionListType,
ExceptionListItemSchema, ExceptionListItemSchema,
UpdateExceptionListItemSchema, UpdateExceptionListItemSchema,
ExceptionListSchema, ExceptionListSchema,
@ -38,7 +37,6 @@ import type {
ExceptionsBuilderReturnExceptionItem, ExceptionsBuilderReturnExceptionItem,
} from '@kbn/securitysolution-list-utils'; } from '@kbn/securitysolution-list-utils';
import { getNewExceptionItem, addIdToEntries } from '@kbn/securitysolution-list-utils'; import { getNewExceptionItem, addIdToEntries } from '@kbn/securitysolution-list-utils';
import type { DataViewBase } from '@kbn/es-query';
import { removeIdFromExceptionItemsEntries } from '@kbn/securitysolution-list-hooks'; import { removeIdFromExceptionItemsEntries } from '@kbn/securitysolution-list-hooks';
import type { EcsSecurityExtension as Ecs, CodeSignature } from '@kbn/securitysolution-ecs'; import type { EcsSecurityExtension as Ecs, CodeSignature } from '@kbn/securitysolution-ecs';
@ -48,10 +46,6 @@ import * as i18n from './translations';
import type { AlertData, Flattened } from './types'; import type { AlertData, Flattened } from './types';
import { WithCopyToClipboard } from '../../../common/lib/clipboard/with_copy_to_clipboard'; import { WithCopyToClipboard } from '../../../common/lib/clipboard/with_copy_to_clipboard';
import exceptionableLinuxFields from './exceptionable_linux_fields.json';
import exceptionableWindowsMacFields from './exceptionable_windows_mac_fields.json';
import exceptionableEndpointFields from './exceptionable_endpoint_fields.json';
import { EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS } from '../../../../common/endpoint/exceptions/exceptionable_endpoint_event_fields';
import { ALERT_ORIGINAL_EVENT } from '../../../../common/field_maps/field_names'; import { ALERT_ORIGINAL_EVENT } from '../../../../common/field_maps/field_names';
import { import {
EVENT_CODE, EVENT_CODE,
@ -65,36 +59,6 @@ import {
ENDPOINT_ALERT, ENDPOINT_ALERT,
} from './highlighted_fields_config'; } from './highlighted_fields_config';
export const filterIndexPatterns = (
patterns: DataViewBase,
type: ExceptionListType,
osTypes?: OsTypeArray
): DataViewBase => {
switch (type) {
case 'endpoint':
const osFilterForEndpoint: (name: string) => boolean = osTypes?.includes('linux')
? (name: string) =>
exceptionableLinuxFields.includes(name) || exceptionableEndpointFields.includes(name)
: (name: string) =>
exceptionableWindowsMacFields.includes(name) ||
exceptionableEndpointFields.includes(name);
return {
...patterns,
fields: patterns.fields.filter(({ name }) => osFilterForEndpoint(name)),
};
case 'endpoint_events':
return {
...patterns,
fields: patterns.fields.filter(({ name }) =>
EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS.includes(name)
),
};
default:
return patterns;
}
};
/** /**
* Formats os value array to a displayable string * Formats os value array to a displayable string
*/ */

View file

@ -192,29 +192,26 @@ export const getArtifactsListTestsData = (): ArtifactsFixtureType[] => [
}, },
{ {
type: 'click', type: 'click',
customSelector: 'button[title="agent.type"]', customSelector: 'button[title="@timestamp"]',
},
{
type: 'click',
selector: 'fieldAutocompleteComboBox',
},
{
type: 'click',
customSelector: 'button[title="agent.type"]',
}, },
{ {
type: 'click', type: 'click',
selector: 'valuesAutocompleteMatch', selector: 'valuesAutocompleteMatch',
}, },
{
type: 'input',
selector: 'valuesAutocompleteMatch',
value: '1234',
},
{ {
type: 'click', type: 'click',
customSelector: 'button[title="endpoint"]', selector: 'eventFilters-form-description-input',
}, },
], ],
checkResults: [ checkResults: [
{ {
selector: 'EventFiltersListPage-card-criteriaConditions-condition', selector: 'EventFiltersListPage-card-criteriaConditions-condition',
value: 'AND agent.typeIS endpoint', value: 'AND @timestampIS 1234',
}, },
], ],
}, },

View file

@ -62,7 +62,6 @@ import type { EffectedPolicySelection } from '../../../../components/effected_po
import { EffectedPolicySelect } from '../../../../components/effected_policy_select'; import { EffectedPolicySelect } from '../../../../components/effected_policy_select';
import { isGlobalPolicyEffected } from '../../../../components/effected_policy_select/utils'; import { isGlobalPolicyEffected } from '../../../../components/effected_policy_select/utils';
import { ExceptionItemComments } from '../../../../../detection_engine/rule_exceptions/components/item_comments'; import { ExceptionItemComments } from '../../../../../detection_engine/rule_exceptions/components/item_comments';
import { filterIndexPatterns } from '../../../../../detection_engine/rule_exceptions/utils/helpers';
import { EventFiltersApiClient } from '../../service/api_client'; import { EventFiltersApiClient } from '../../service/api_client';
const OPERATING_SYSTEMS: readonly OperatingSystem[] = [ const OPERATING_SYSTEMS: readonly OperatingSystem[] = [
@ -452,7 +451,6 @@ export const EventFiltersForm: React.FC<ArtifactFormComponentProps & { allowSele
dataTestSubj: 'alert-exception-builder', dataTestSubj: 'alert-exception-builder',
idAria: 'alert-exception-builder', idAria: 'alert-exception-builder',
onChange: handleOnBuilderChange, onChange: handleOnBuilderChange,
listTypeSpecificIndexPatternFilter: filterIndexPatterns,
operatorsList: EVENT_FILTERS_OPERATORS, operatorsList: EVENT_FILTERS_OPERATORS,
osTypes: exception.os_types, osTypes: exception.os_types,
}), }),

View file

@ -41,7 +41,6 @@ import { EndpointActionGenerator } from '../../../../common/endpoint/data_genera
import { getEndpointAuthzInitialStateMock } from '../../../../common/endpoint/service/authz/mocks'; import { getEndpointAuthzInitialStateMock } from '../../../../common/endpoint/service/authz/mocks';
import { eventsIndexPattern, SUGGESTIONS_ROUTE } from '../../../../common/endpoint/constants'; import { eventsIndexPattern, SUGGESTIONS_ROUTE } from '../../../../common/endpoint/constants';
import { EndpointAppContextService } from '../../endpoint_app_context_services'; import { EndpointAppContextService } from '../../endpoint_app_context_services';
import { EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS } from '../../../../common/endpoint/exceptions/exceptionable_endpoint_event_fields';
jest.mock('@kbn/unified-search-plugin/server/autocomplete/terms_enum', () => { jest.mock('@kbn/unified-search-plugin/server/autocomplete/terms_enum', () => {
return { return {
@ -93,7 +92,7 @@ describe('when calling the Suggestions route handler', () => {
createRouteHandlerContext(mockScopedEsClient, mockSavedObjectClient) createRouteHandlerContext(mockScopedEsClient, mockSavedObjectClient)
); );
const fieldName = EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS[0]; const fieldName = 'process.id';
const mockRequest = httpServerMock.createKibanaRequest< const mockRequest = httpServerMock.createKibanaRequest<
TypeOf<typeof EndpointSuggestionsSchema.params>, TypeOf<typeof EndpointSuggestionsSchema.params>,
never, never,
@ -101,7 +100,7 @@ describe('when calling the Suggestions route handler', () => {
>({ >({
params: { suggestion_type: 'eventFilters' }, params: { suggestion_type: 'eventFilters' },
body: { body: {
field: fieldName, field: 'process.id',
query: 'test-query', query: 'test-query',
filters: 'test-filters', filters: 'test-filters',
fieldMeta: 'test-field-meta', fieldMeta: 'test-field-meta',
@ -149,36 +148,6 @@ describe('when calling the Suggestions route handler', () => {
body: 'Invalid suggestion_type: any', body: 'Invalid suggestion_type: any',
}); });
}); });
it('should respond with bad request if wrong field name', async () => {
applyActionsEsSearchMock(
mockScopedEsClient.asInternalUser,
new EndpointActionGenerator().toEsSearchResponse([])
);
const mockContext = requestContextMock.convertContext(
createRouteHandlerContext(mockScopedEsClient, mockSavedObjectClient)
);
const mockRequest = httpServerMock.createKibanaRequest<
TypeOf<typeof EndpointSuggestionsSchema.params>,
never,
never
>({
params: { suggestion_type: 'eventFilters' },
body: {
field: 'test-field',
query: 'test-query',
filters: 'test-filters',
fieldMeta: 'test-field-meta',
},
});
await suggestionsRouteHandler(mockContext, mockRequest, mockResponse);
expect(mockResponse.badRequest).toHaveBeenCalledWith({
body: 'Unsupported field name: test-field',
});
});
}); });
describe('without having right privileges', () => { describe('without having right privileges', () => {
beforeEach(() => { beforeEach(() => {

View file

@ -12,7 +12,6 @@ import type { TypeOf } from '@kbn/config-schema';
import { getRequestAbortedSignal } from '@kbn/data-plugin/server'; import { getRequestAbortedSignal } from '@kbn/data-plugin/server';
import type { ConfigSchema } from '@kbn/unified-search-plugin/config'; import type { ConfigSchema } from '@kbn/unified-search-plugin/config';
import { termsEnumSuggestions } from '@kbn/unified-search-plugin/server/autocomplete/terms_enum'; import { termsEnumSuggestions } from '@kbn/unified-search-plugin/server/autocomplete/terms_enum';
import { EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS } from '../../../../common/endpoint/exceptions/exceptionable_endpoint_event_fields';
import { import {
type EndpointSuggestionsBody, type EndpointSuggestionsBody,
EndpointSuggestionsSchema, EndpointSuggestionsSchema,
@ -71,11 +70,6 @@ export const getEndpointSuggestionsRequestHandler = (
let index = ''; let index = '';
if (request.params.suggestion_type === 'eventFilters') { if (request.params.suggestion_type === 'eventFilters') {
if (!EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS.includes(fieldName)) {
return response.badRequest({
body: `Unsupported field name: ${fieldName}`,
});
}
index = eventsIndexPattern; index = eventsIndexPattern;
} else { } else {
return response.badRequest({ return response.badRequest({

View file

@ -13,25 +13,18 @@ import type {
CreateExceptionListItemOptions, CreateExceptionListItemOptions,
UpdateExceptionListItemOptions, UpdateExceptionListItemOptions,
} from '@kbn/lists-plugin/server'; } from '@kbn/lists-plugin/server';
import { EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS } from '../../../../common/endpoint/exceptions/exceptionable_endpoint_event_fields';
import type { ExceptionItemLikeOptions } from '../types'; import type { ExceptionItemLikeOptions } from '../types';
import { BaseValidator } from './base_validator'; import { BaseValidator } from './base_validator';
import { EndpointArtifactExceptionValidationError } from './errors'; import { EndpointArtifactExceptionValidationError } from './errors';
function validateField(field: string) {
if (!EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS.includes(field)) {
return `invalid field: ${field}`;
}
}
const EventFilterDataSchema = schema.object( const EventFilterDataSchema = schema.object(
{ {
entries: schema.arrayOf( entries: schema.arrayOf(
schema.object( schema.object(
{ {
field: schema.string({ validate: validateField }), field: schema.string(),
}, },
{ unknowns: 'ignore' } { unknowns: 'ignore' }
), ),

View file

@ -207,21 +207,22 @@ export const getArtifactsListTestsData = () => [
}, },
{ {
type: 'customClick', type: 'customClick',
selector: 'button[title="agent.type"]', selector: 'button[title="agent.ephemeral_id"]',
}, },
{ {
type: 'click', type: 'click',
selector: 'valuesAutocompleteMatch', selector: 'valuesAutocompleteMatch',
}, },
{ {
type: 'customClick', type: 'input',
selector: 'button[title="endpoint"]', selector: 'valuesAutocompleteMatch',
value: 'endpoint',
}, },
], ],
checkResults: [ checkResults: [
{ {
selector: 'EventFiltersListPage-card-criteriaConditions-condition', selector: 'EventFiltersListPage-card-criteriaConditions-condition',
value: 'AND agent.typeIS endpoint', value: 'AND agent.ephemeral_idIS endpoint',
}, },
], ],
}, },
@ -243,7 +244,7 @@ export const getArtifactsListTestsData = () => [
}, },
{ {
type: 'customClick', type: 'customClick',
selector: 'button[title="agent.name"]', selector: 'button[title="agent.id"]',
}, },
{ {
type: 'input', type: 'input',
@ -258,7 +259,7 @@ export const getArtifactsListTestsData = () => [
checkResults: [ checkResults: [
{ {
selector: 'EventFiltersListPage-card-criteriaConditions-condition', selector: 'EventFiltersListPage-card-criteriaConditions-condition',
value: 'AND agent.nameIS test super large value', value: 'AND agent.idIS test super large value',
}, },
{ {
selector: 'EventFiltersListPage-card-header-title', selector: 'EventFiltersListPage-card-header-title',
@ -269,7 +270,7 @@ export const getArtifactsListTestsData = () => [
value: 'This is the event filter description edited', value: 'This is the event filter description edited',
}, },
], ],
waitForValue: 'AND agent.nameIS test super large value', waitForValue: 'AND agent.idIS test super large value',
}, },
delete: { delete: {
confirmSelector: 'EventFiltersListPage-deleteModal-submitButton', confirmSelector: 'EventFiltersListPage-deleteModal-submitButton',
@ -283,17 +284,17 @@ export const getArtifactsListTestsData = () => [
getExpectedUpdatedtArtifactWhenCreate: (): ArtifactElasticsearchProperties => ({ getExpectedUpdatedtArtifactWhenCreate: (): ArtifactElasticsearchProperties => ({
type: 'eventfilterlist', type: 'eventfilterlist',
identifier: 'endpoint-eventfilterlist-windows-v1', identifier: 'endpoint-eventfilterlist-windows-v1',
body: 'eJxVzFEKgCAQBNC77Ld0AK8SEYtusWAqukYh3b1F+on5ezNMB4pSmCrYuYPcmcBC5SMHAvPrNqbgtcRddRpLAylTQUlFnaMLzZNX/W7oQierwzrwxNCGRp8TR4Fn0bwiRSx6', body: 'eJxVjEEKwzAMBP+ic+kD8pUSgrA3qUCxha2EltC/Vwm9lL0sM8sehOJN0Gl4HORvAw3UZTUF3f7cLNAckpegd9gTKxrrJDmG1aJ7beGlJN0yTvq7w4uTT4n7BXfW7aIlW5Xi9BkjX6sIL5c=',
package_name: 'endpoint', package_name: 'endpoint',
created: '2000-01-01T00:00:00.000Z', created: '2000-01-01T00:00:00.000Z',
relative_url: relative_url:
'/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/54e692d3d896a72ba8b0ccc1e174d9c24d43e427ea88a42ddba8ec0839a37fec', '/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/b3373c93ffc795d954f22c625c084dc5874a156ec0cb3d4af1c3dab0b965fa30',
compression_algorithm: 'zlib', compression_algorithm: 'zlib',
decoded_size: 128, decoded_size: 136,
decoded_sha256: '54e692d3d896a72ba8b0ccc1e174d9c24d43e427ea88a42ddba8ec0839a37fec', decoded_sha256: 'b3373c93ffc795d954f22c625c084dc5874a156ec0cb3d4af1c3dab0b965fa30',
encryption_algorithm: 'none', encryption_algorithm: 'none',
encoded_sha256: '3f3f689efc895ada36b232b71d63f93b9b9552f84d395689f828429017016b46', encoded_sha256: 'c1b30df9457ba007065fff1388c026ad269e63fbed535b506ac559fd616aabe9',
encoded_size: 99, encoded_size: 107,
}), }),
getExpectedUpdatedArtifactBodyWhenCreate: (): ArtifactBodyType => ({ getExpectedUpdatedArtifactBodyWhenCreate: (): ArtifactBodyType => ({
entries: [ entries: [
@ -301,7 +302,7 @@ export const getArtifactsListTestsData = () => [
type: 'simple', type: 'simple',
entries: [ entries: [
{ {
field: 'agent.type', field: 'agent.ephemeral_id',
operator: 'included', operator: 'included',
type: 'exact_cased', type: 'exact_cased',
value: 'endpoint', value: 'endpoint',
@ -313,17 +314,17 @@ export const getArtifactsListTestsData = () => [
getExpectedUpdatedArtifactWhenUpdate: (): ArtifactElasticsearchProperties => ({ getExpectedUpdatedArtifactWhenUpdate: (): ArtifactElasticsearchProperties => ({
type: 'eventfilterlist', type: 'eventfilterlist',
identifier: 'endpoint-eventfilterlist-windows-v1', identifier: 'endpoint-eventfilterlist-windows-v1',
body: 'eJxVjFEKgzAQRK8S9rt4AK8ipSzJKIE1huxGWsS7u9L+lPl7b2YOQrGWoTROB9mngkbSvFYBPf7cnCHJJS9Oh8LrXdgqGtvWnOcSpSckp78bvDnaK7JCoOp8Z+m3MKgF7b4Nwm1B+Irz6bkASPAywg==', body: 'eJxVzEEKwkAMheGrDFmLB+hVikiYeS2B2A6TjCildze1biS77+dlIyzeBEbDuJG/K2ggk0dV0OWvTQItEXkOvUqJvFY09rWFypK1Fxz6e4IXZ79nti8+WfuhDvNkPYZJuc1IZ9hvcR86lDCb',
package_name: 'endpoint', package_name: 'endpoint',
created: '2000-01-01T00:00:00.000Z', created: '2000-01-01T00:00:00.000Z',
relative_url: relative_url:
'/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/49b7181f97ea4c92dd8457cabb6d67bde7e05d02a7f41ce8ae40ff2e5819e098', '/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/e4f00c88380d2c429eeb2741ad19383b94d76f79744b098b095befc24003e158',
compression_algorithm: 'zlib', compression_algorithm: 'zlib',
decoded_size: 145, decoded_size: 140,
decoded_sha256: '49b7181f97ea4c92dd8457cabb6d67bde7e05d02a7f41ce8ae40ff2e5819e098', decoded_sha256: 'e4f00c88380d2c429eeb2741ad19383b94d76f79744b098b095befc24003e158',
encryption_algorithm: 'none', encryption_algorithm: 'none',
encoded_sha256: 'f852031403be242a4190b9c5ea2726706877bb0d45fe9b21f8b297ed11ab1d7c', encoded_sha256: '99386e3d9a67eac88f0a4cc4ac36ad42cfda42598ce0ee1c11a8afc50bf004fe',
encoded_size: 112, encoded_size: 108,
}), }),
getExpectedUpdatedArtifactBodyWhenUpdate: (): ArtifactBodyType => ({ getExpectedUpdatedArtifactBodyWhenUpdate: (): ArtifactBodyType => ({
entries: [ entries: [
@ -331,9 +332,9 @@ export const getArtifactsListTestsData = () => [
type: 'simple', type: 'simple',
entries: [ entries: [
{ {
field: 'agent.name', field: 'agent.id',
operator: 'included', operator: 'included',
type: 'exact_caseless', type: 'exact_cased',
value: 'test super large value', value: 'test super large value',
}, },
], ],

View file

@ -178,20 +178,6 @@ export default function ({ getService }: FtrProviderContext) {
describe('and has authorization to manage endpoint security', () => { describe('and has authorization to manage endpoint security', () => {
for (const eventFilterApiCall of eventFilterCalls) { for (const eventFilterApiCall of eventFilterCalls) {
it(`should error on [${eventFilterApiCall.method}] if invalid field`, async () => {
const body = eventFilterApiCall.getBody({});
body.entries[0].field = 'some.invalid.field';
await supertestWithoutAuth[eventFilterApiCall.method](eventFilterApiCall.path)
.auth(ROLE.endpoint_security_policy_manager, 'changeme')
.set('kbn-xsrf', 'true')
.send(body)
.expect(400)
.expect(anEndpointArtifactError)
.expect(anErrorMessageWith(/invalid field: some\.invalid\.field/));
});
it(`should error on [${eventFilterApiCall.method}] if more than one OS is set`, async () => { it(`should error on [${eventFilterApiCall.method}] if more than one OS is set`, async () => {
const body = eventFilterApiCall.getBody({ os_types: ['linux', 'windows'] }); const body = eventFilterApiCall.getBody({ os_types: ['linux', 'windows'] });