mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[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:
parent
7e2ba48c18
commit
1a3aefe6ec
25 changed files with 61 additions and 943 deletions
|
@ -19,7 +19,6 @@ import {
|
|||
NamespaceType,
|
||||
ListOperatorEnum as OperatorEnum,
|
||||
ListOperatorTypeEnum as OperatorTypeEnum,
|
||||
OsTypeArray,
|
||||
createExceptionListItemSchema,
|
||||
entriesList,
|
||||
entriesNested,
|
||||
|
@ -302,18 +301,13 @@ export const getUpdatedEntriesOnDelete = (
|
|||
*/
|
||||
export const getFilteredIndexPatterns = (
|
||||
patterns: DataViewBase,
|
||||
item: FormattedBuilderEntry,
|
||||
type: ExceptionListType,
|
||||
preFilter?: (i: DataViewBase, t: ExceptionListType, o?: OsTypeArray) => DataViewBase,
|
||||
osTypes?: OsTypeArray
|
||||
item: FormattedBuilderEntry
|
||||
): DataViewBase => {
|
||||
const indexPatterns = preFilter != null ? preFilter(patterns, type, osTypes) : patterns;
|
||||
|
||||
if (item.nested === 'child' && item.parent != null) {
|
||||
// when user has selected a nested entry, only fields with the common parent are shown
|
||||
return {
|
||||
...indexPatterns,
|
||||
fields: indexPatterns.fields
|
||||
...patterns,
|
||||
fields: patterns.fields
|
||||
.filter((indexField) => {
|
||||
const subTypeNested = getDataViewFieldSubtypeNested(indexField);
|
||||
const fieldHasCommonParentPath =
|
||||
|
@ -330,15 +324,15 @@ export const getFilteredIndexPatterns = (
|
|||
};
|
||||
} else if (item.nested === 'parent' && item.field != null) {
|
||||
// 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) {
|
||||
// when user selects to add a nested entry, only nested fields are shown as options
|
||||
return {
|
||||
...indexPatterns,
|
||||
fields: indexPatterns.fields.filter((field) => isDataViewFieldSubtypeNested(field)),
|
||||
...patterns,
|
||||
fields: patterns.fields.filter((field) => isDataViewFieldSubtypeNested(field)),
|
||||
};
|
||||
} else {
|
||||
return indexPatterns;
|
||||
return patterns;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -190,13 +190,6 @@ export default {
|
|||
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: {
|
||||
description:
|
||||
'`(arg: OnChangeProps) => void` - callback invoked any time builder update to propagate changes up to parent.',
|
||||
|
|
|
@ -76,11 +76,6 @@ export interface EntryItemProps {
|
|||
showLabel: boolean;
|
||||
osTypes?: OsTypeArray;
|
||||
listType: ExceptionListType;
|
||||
listTypeSpecificIndexPatternFilter?: (
|
||||
pattern: DataViewBase,
|
||||
type: ExceptionListType,
|
||||
osTypes?: OsTypeArray
|
||||
) => DataViewBase;
|
||||
onChange: (arg: BuilderEntry, i: number) => void;
|
||||
onlyShowListOperators?: boolean;
|
||||
setErrorsExist: (arg: EntryFieldError) => void;
|
||||
|
@ -99,7 +94,6 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
indexPattern,
|
||||
osTypes,
|
||||
listType,
|
||||
listTypeSpecificIndexPatternFilter,
|
||||
onChange,
|
||||
onlyShowListOperators = false,
|
||||
setErrorsExist,
|
||||
|
@ -204,13 +198,7 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
|
||||
const renderFieldInput = useCallback(
|
||||
(isFirst: boolean): JSX.Element => {
|
||||
const filteredIndexPatterns = getFilteredIndexPatterns(
|
||||
indexPattern,
|
||||
entry,
|
||||
listType,
|
||||
listTypeSpecificIndexPatternFilter,
|
||||
osTypes
|
||||
);
|
||||
const filteredIndexPatterns = getFilteredIndexPatterns(indexPattern, entry);
|
||||
const comboBox = (
|
||||
<FieldComponent
|
||||
placeholder={
|
||||
|
@ -312,9 +300,6 @@ export const BuilderEntryItem: React.FC<EntryItemProps> = ({
|
|||
[
|
||||
indexPattern,
|
||||
entry,
|
||||
listType,
|
||||
listTypeSpecificIndexPatternFilter,
|
||||
osTypes,
|
||||
isDisabled,
|
||||
handleFieldChange,
|
||||
allowCustomOptions,
|
||||
|
|
|
@ -53,11 +53,6 @@ interface BuilderExceptionListItemProps {
|
|||
andLogicIncluded: boolean;
|
||||
isOnlyItem: boolean;
|
||||
listType: ExceptionListType;
|
||||
listTypeSpecificIndexPatternFilter?: (
|
||||
pattern: DataViewBase,
|
||||
type: ExceptionListType,
|
||||
osTypes?: OsTypeArray
|
||||
) => DataViewBase;
|
||||
onDeleteExceptionItem: (item: ExceptionsBuilderExceptionItem, index: number) => void;
|
||||
onChangeExceptionItem: (item: ExceptionsBuilderExceptionItem, index: number) => void;
|
||||
setErrorsExist: (arg: EntryFieldError) => void;
|
||||
|
@ -80,7 +75,6 @@ export const BuilderExceptionListItemComponent = React.memo<BuilderExceptionList
|
|||
indexPattern,
|
||||
isOnlyItem,
|
||||
listType,
|
||||
listTypeSpecificIndexPatternFilter,
|
||||
andLogicIncluded,
|
||||
onDeleteExceptionItem,
|
||||
onChangeExceptionItem,
|
||||
|
@ -152,7 +146,6 @@ export const BuilderExceptionListItemComponent = React.memo<BuilderExceptionList
|
|||
httpService={httpService}
|
||||
indexPattern={indexPattern}
|
||||
listType={listType}
|
||||
listTypeSpecificIndexPatternFilter={listTypeSpecificIndexPatternFilter}
|
||||
onChange={handleEntryChange}
|
||||
onlyShowListOperators={onlyShowListOperators}
|
||||
setErrorsExist={setErrorsExist}
|
||||
|
|
|
@ -89,10 +89,6 @@ export interface ExceptionBuilderProps {
|
|||
listId: string | undefined;
|
||||
listNamespaceType: NamespaceType | undefined;
|
||||
listType: ExceptionListType;
|
||||
listTypeSpecificIndexPatternFilter?: (
|
||||
pattern: DataViewBase,
|
||||
type: ExceptionListType
|
||||
) => DataViewBase;
|
||||
onChange: (arg: OnChangeProps) => void;
|
||||
ruleName?: string;
|
||||
isDisabled?: boolean;
|
||||
|
@ -115,7 +111,6 @@ export const ExceptionBuilderComponent = ({
|
|||
listId,
|
||||
listNamespaceType,
|
||||
listType,
|
||||
listTypeSpecificIndexPatternFilter,
|
||||
onChange,
|
||||
ruleName,
|
||||
exceptionItemName,
|
||||
|
@ -461,7 +456,6 @@ export const ExceptionBuilderComponent = ({
|
|||
isOnlyItem={exceptions.length === 1}
|
||||
key={getExceptionListItemId(exceptionListItem, index)}
|
||||
listType={listType}
|
||||
listTypeSpecificIndexPatternFilter={listTypeSpecificIndexPatternFilter}
|
||||
onChangeExceptionItem={handleExceptionItemChange}
|
||||
onDeleteExceptionItem={handleDeleteExceptionItem}
|
||||
onlyShowListOperators={containsValueListEntry(exceptions)}
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
EntryMatch,
|
||||
EntryMatchAny,
|
||||
EntryNested,
|
||||
ExceptionListType,
|
||||
ListOperatorEnum as OperatorEnum,
|
||||
ListOperatorTypeEnum as OperatorTypeEnum,
|
||||
} from '@kbn/securitysolution-io-ts-list-types';
|
||||
|
@ -168,24 +167,13 @@ const mockEndpointFields = [
|
|||
export const getEndpointField = (name: string): 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('#getFilteredIndexPatterns', () => {
|
||||
describe('list type detections', () => {
|
||||
test('it returns nested fields that match parent value when "item.nested" is "child"', () => {
|
||||
const payloadIndexPattern = getMockIndexPattern();
|
||||
const payloadItem: FormattedBuilderEntry = getMockNestedBuilderEntry();
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem, 'detection');
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
|
||||
const expected: DataViewBase = {
|
||||
fields: [{ ...getField('nestedField.child'), name: 'child' }],
|
||||
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', () => {
|
||||
const payloadIndexPattern = getMockIndexPattern();
|
||||
const payloadItem: FormattedBuilderEntry = getMockNestedParentBuilderEntry();
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem, 'detection');
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
|
||||
const expected: DataViewBase & { fields: Array<Partial<FieldSpec>> } = {
|
||||
fields: [{ ...getField('nestedField.child'), esTypes: ['nested'], name: 'nestedField' }],
|
||||
id: '1234',
|
||||
|
@ -212,7 +200,7 @@ describe('Exception builder helpers', () => {
|
|||
...getMockNestedParentBuilderEntry(),
|
||||
field: undefined,
|
||||
};
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem, 'detection');
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
|
||||
const expected: DataViewBase = {
|
||||
fields: [
|
||||
{ ...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"', () => {
|
||||
const payloadIndexPattern = getMockIndexPattern();
|
||||
const payloadItem: FormattedBuilderEntry = getMockBuilderEntry();
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem, 'detection');
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
|
||||
const expected: DataViewBase = {
|
||||
fields: [...fields],
|
||||
id: '1234',
|
||||
|
@ -265,7 +253,7 @@ describe('Exception builder helpers', () => {
|
|||
},
|
||||
value: 'some value',
|
||||
};
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem, 'endpoint');
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
|
||||
const expected: DataViewBase = {
|
||||
fields: [{ ...getEndpointField('file.Ext.code_signature.status'), name: 'status' }],
|
||||
id: '1234',
|
||||
|
@ -284,7 +272,7 @@ describe('Exception builder helpers', () => {
|
|||
...getMockNestedParentBuilderEntry(),
|
||||
field,
|
||||
};
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem, 'endpoint');
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
|
||||
const fieldsExpected: FieldSpec[] = [
|
||||
{
|
||||
aggregatable: false,
|
||||
|
@ -315,53 +303,13 @@ describe('Exception builder helpers', () => {
|
|||
...getMockNestedParentBuilderEntry(),
|
||||
field: undefined,
|
||||
};
|
||||
const output = getFilteredIndexPatterns(
|
||||
payloadIndexPattern,
|
||||
payloadItem,
|
||||
'endpoint',
|
||||
filterIndexPatterns
|
||||
);
|
||||
const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem);
|
||||
const expected: DataViewBase = {
|
||||
fields: [getEndpointField('file.Ext.code_signature.status')],
|
||||
id: '1234',
|
||||
title: 'logstash-*',
|
||||
};
|
||||
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,
|
||||
fields: [
|
||||
{ ...getField('nestedField.child') },
|
||||
{ ...getField('nestedField.nestedChild.doublyNestedChild') },
|
||||
getEndpointField('file.Ext.code_signature.status'),
|
||||
],
|
||||
id: '1234',
|
||||
title: 'logstash-*',
|
||||
};
|
||||
|
|
|
@ -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',
|
||||
];
|
|
@ -23,7 +23,7 @@ import {
|
|||
} from '../../../tasks/create_new_rule';
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation';
|
||||
import {
|
||||
addExceptionEntryFieldValue,
|
||||
addExceptionEntryFieldValueAndSelectSuggestion,
|
||||
addExceptionEntryFieldValueValue,
|
||||
addExceptionFlyoutItemName,
|
||||
editExceptionFlyoutItemName,
|
||||
|
@ -98,7 +98,7 @@ describe('Endpoint Exceptions workflows from Alert', () => {
|
|||
|
||||
cy.get(ADD_AND_BTN).click();
|
||||
// edit conditions
|
||||
addExceptionEntryFieldValue(ADDITIONAL_ENTRY, 6);
|
||||
addExceptionEntryFieldValueAndSelectSuggestion(ADDITIONAL_ENTRY, 6);
|
||||
addExceptionEntryFieldValueValue('foo', 4);
|
||||
|
||||
// Change the name again
|
||||
|
|
|
@ -99,6 +99,11 @@ export const addExceptionEntryFieldValue = (field: string, index = 0) => {
|
|||
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) => {
|
||||
cy.get(OPERATOR_INPUT).eq(index).type(`${operator}{enter}`);
|
||||
cy.get(EXCEPTION_FLYOUT_TITLE).click();
|
||||
|
|
|
@ -40,7 +40,6 @@ import { ExceptionItemComments } from '../item_comments';
|
|||
import {
|
||||
defaultEndpointExceptionItems,
|
||||
retrieveAlertOsTypes,
|
||||
filterIndexPatterns,
|
||||
getPrepopulatedRuleExceptionWithHighlightFields,
|
||||
} from '../../utils/helpers';
|
||||
import type { AlertData } from '../../utils/types';
|
||||
|
@ -515,7 +514,6 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({
|
|||
onOsChange={setSelectedOs}
|
||||
onExceptionItemAdd={setExceptionItemsToAdd}
|
||||
onSetErrorExists={setConditionsValidationError}
|
||||
onFilterIndexPatterns={filterIndexPatterns}
|
||||
getExtendedFields={getExtendedFields}
|
||||
/>
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ import { ExceptionsLinkedToRule } from '../flyout_components/linked_to_rule';
|
|||
import { ExceptionItemsFlyoutAlertsActions } from '../flyout_components/alerts_actions';
|
||||
import { ExceptionsConditions } from '../flyout_components/item_conditions';
|
||||
|
||||
import { filterIndexPatterns } from '../../utils/helpers';
|
||||
import { useFetchIndexPatterns } from '../../logic/use_exception_flyout_data';
|
||||
import { useCloseAlertsFromExceptions } from '../../logic/use_close_alerts';
|
||||
import { useFindExceptionListReferences } from '../../logic/use_find_references';
|
||||
|
@ -369,7 +368,6 @@ const EditExceptionFlyoutComponent: React.FC<EditExceptionFlyoutProps> = ({
|
|||
isEdit
|
||||
onExceptionItemAdd={setExceptionItemsToAdd}
|
||||
onSetErrorExists={setConditionsValidationError}
|
||||
onFilterIndexPatterns={filterIndexPatterns}
|
||||
getExtendedFields={getExtendedFields}
|
||||
/>
|
||||
{!openedFromListDetailPage && listType === ExceptionListTypeEnum.DETECTION && (
|
||||
|
|
|
@ -41,7 +41,6 @@ describe('ExceptionsConditions', () => {
|
|||
onOsChange={jest.fn()}
|
||||
onExceptionItemAdd={jest.fn()}
|
||||
onSetErrorExists={jest.fn()}
|
||||
onFilterIndexPatterns={jest.fn()}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
@ -72,7 +71,6 @@ describe('ExceptionsConditions', () => {
|
|||
onOsChange={jest.fn()}
|
||||
onExceptionItemAdd={jest.fn()}
|
||||
onSetErrorExists={jest.fn()}
|
||||
onFilterIndexPatterns={jest.fn()}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
@ -102,7 +100,6 @@ describe('ExceptionsConditions', () => {
|
|||
onOsChange={jest.fn()}
|
||||
onExceptionItemAdd={jest.fn()}
|
||||
onSetErrorExists={jest.fn()}
|
||||
onFilterIndexPatterns={jest.fn()}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
@ -132,7 +129,6 @@ describe('ExceptionsConditions', () => {
|
|||
onOsChange={jest.fn()}
|
||||
onExceptionItemAdd={jest.fn()}
|
||||
onSetErrorExists={jest.fn()}
|
||||
onFilterIndexPatterns={jest.fn()}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
@ -165,7 +161,6 @@ describe('ExceptionsConditions', () => {
|
|||
onOsChange={jest.fn()}
|
||||
onExceptionItemAdd={jest.fn()}
|
||||
onSetErrorExists={jest.fn()}
|
||||
onFilterIndexPatterns={jest.fn()}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
@ -196,7 +191,6 @@ describe('ExceptionsConditions', () => {
|
|||
onOsChange={jest.fn()}
|
||||
onExceptionItemAdd={jest.fn()}
|
||||
onSetErrorExists={jest.fn()}
|
||||
onFilterIndexPatterns={jest.fn()}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
|
|
@ -85,11 +85,6 @@ interface ExceptionsFlyoutConditionsComponentProps {
|
|||
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 */
|
||||
onSetErrorExists: (errorExists: boolean) => void;
|
||||
onFilterIndexPatterns: (
|
||||
patterns: DataViewBase,
|
||||
type: ExceptionListType,
|
||||
osTypes?: Array<'linux' | 'macos' | 'windows'> | undefined
|
||||
) => DataViewBase;
|
||||
|
||||
getExtendedFields?: (fields: string[]) => Promise<DataViewField[]>;
|
||||
}
|
||||
|
@ -107,7 +102,6 @@ const ExceptionsConditionsComponent: React.FC<ExceptionsFlyoutConditionsComponen
|
|||
onOsChange,
|
||||
onExceptionItemAdd,
|
||||
onSetErrorExists,
|
||||
onFilterIndexPatterns,
|
||||
getExtendedFields,
|
||||
}): JSX.Element => {
|
||||
const { http, unifiedSearch } = useKibana().services;
|
||||
|
@ -260,7 +254,6 @@ const ExceptionsConditionsComponent: React.FC<ExceptionsFlyoutConditionsComponen
|
|||
osTypes,
|
||||
listId: listIdToUse,
|
||||
listNamespaceType,
|
||||
listTypeSpecificIndexPatternFilter: onFilterIndexPatterns,
|
||||
exceptionItemName,
|
||||
indexPatterns,
|
||||
isOrDisabled: isExceptionBuilderFormDisabled,
|
||||
|
|
|
@ -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"
|
||||
]
|
|
@ -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"
|
||||
]
|
|
@ -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"
|
||||
]
|
|
@ -23,7 +23,6 @@ import {
|
|||
getFileCodeSignature,
|
||||
getProcessCodeSignature,
|
||||
retrieveAlertOsTypes,
|
||||
filterIndexPatterns,
|
||||
getCodeSignatureValue,
|
||||
buildRuleExceptionWithConditions,
|
||||
buildExceptionEntriesFromAlertFields,
|
||||
|
@ -39,12 +38,10 @@ import type {
|
|||
ExceptionListItemSchema,
|
||||
} 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 { getEntryMatchMock } from '@kbn/lists-plugin/common/schemas/types/entry_match.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 type { CodeSignature } from '@kbn/securitysolution-ecs';
|
||||
import {
|
||||
|
@ -56,49 +53,6 @@ jest.mock('uuid', () => ({
|
|||
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', () => {
|
||||
beforeEach(() => {
|
||||
moment.tz.setDefault('UTC');
|
||||
|
@ -108,35 +62,6 @@ describe('Exception helpers', () => {
|
|||
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', () => {
|
||||
test('it returns null if no operating system tag specified', () => {
|
||||
const result = formatOperatingSystems(['some os', 'some other os']);
|
||||
|
|
|
@ -20,7 +20,6 @@ import type {
|
|||
NamespaceType,
|
||||
EntryNested,
|
||||
OsTypeArray,
|
||||
ExceptionListType,
|
||||
ExceptionListItemSchema,
|
||||
UpdateExceptionListItemSchema,
|
||||
ExceptionListSchema,
|
||||
|
@ -38,7 +37,6 @@ import type {
|
|||
ExceptionsBuilderReturnExceptionItem,
|
||||
} 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 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 { 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 {
|
||||
EVENT_CODE,
|
||||
|
@ -65,36 +59,6 @@ import {
|
|||
ENDPOINT_ALERT,
|
||||
} 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
|
||||
*/
|
||||
|
|
|
@ -192,29 +192,26 @@ export const getArtifactsListTestsData = (): ArtifactsFixtureType[] => [
|
|||
},
|
||||
{
|
||||
type: 'click',
|
||||
customSelector: 'button[title="agent.type"]',
|
||||
},
|
||||
{
|
||||
type: 'click',
|
||||
selector: 'fieldAutocompleteComboBox',
|
||||
},
|
||||
{
|
||||
type: 'click',
|
||||
customSelector: 'button[title="agent.type"]',
|
||||
customSelector: 'button[title="@timestamp"]',
|
||||
},
|
||||
{
|
||||
type: 'click',
|
||||
selector: 'valuesAutocompleteMatch',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
selector: 'valuesAutocompleteMatch',
|
||||
value: '1234',
|
||||
},
|
||||
{
|
||||
type: 'click',
|
||||
customSelector: 'button[title="endpoint"]',
|
||||
selector: 'eventFilters-form-description-input',
|
||||
},
|
||||
],
|
||||
checkResults: [
|
||||
{
|
||||
selector: 'EventFiltersListPage-card-criteriaConditions-condition',
|
||||
value: 'AND agent.typeIS endpoint',
|
||||
value: 'AND @timestampIS 1234',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -62,7 +62,6 @@ import type { EffectedPolicySelection } from '../../../../components/effected_po
|
|||
import { EffectedPolicySelect } from '../../../../components/effected_policy_select';
|
||||
import { isGlobalPolicyEffected } from '../../../../components/effected_policy_select/utils';
|
||||
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';
|
||||
|
||||
const OPERATING_SYSTEMS: readonly OperatingSystem[] = [
|
||||
|
@ -452,7 +451,6 @@ export const EventFiltersForm: React.FC<ArtifactFormComponentProps & { allowSele
|
|||
dataTestSubj: 'alert-exception-builder',
|
||||
idAria: 'alert-exception-builder',
|
||||
onChange: handleOnBuilderChange,
|
||||
listTypeSpecificIndexPatternFilter: filterIndexPatterns,
|
||||
operatorsList: EVENT_FILTERS_OPERATORS,
|
||||
osTypes: exception.os_types,
|
||||
}),
|
||||
|
|
|
@ -41,7 +41,6 @@ import { EndpointActionGenerator } from '../../../../common/endpoint/data_genera
|
|||
import { getEndpointAuthzInitialStateMock } from '../../../../common/endpoint/service/authz/mocks';
|
||||
import { eventsIndexPattern, SUGGESTIONS_ROUTE } from '../../../../common/endpoint/constants';
|
||||
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', () => {
|
||||
return {
|
||||
|
@ -93,7 +92,7 @@ describe('when calling the Suggestions route handler', () => {
|
|||
createRouteHandlerContext(mockScopedEsClient, mockSavedObjectClient)
|
||||
);
|
||||
|
||||
const fieldName = EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS[0];
|
||||
const fieldName = 'process.id';
|
||||
const mockRequest = httpServerMock.createKibanaRequest<
|
||||
TypeOf<typeof EndpointSuggestionsSchema.params>,
|
||||
never,
|
||||
|
@ -101,7 +100,7 @@ describe('when calling the Suggestions route handler', () => {
|
|||
>({
|
||||
params: { suggestion_type: 'eventFilters' },
|
||||
body: {
|
||||
field: fieldName,
|
||||
field: 'process.id',
|
||||
query: 'test-query',
|
||||
filters: 'test-filters',
|
||||
fieldMeta: 'test-field-meta',
|
||||
|
@ -149,36 +148,6 @@ describe('when calling the Suggestions route handler', () => {
|
|||
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', () => {
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -12,7 +12,6 @@ import type { TypeOf } from '@kbn/config-schema';
|
|||
import { getRequestAbortedSignal } from '@kbn/data-plugin/server';
|
||||
import type { ConfigSchema } from '@kbn/unified-search-plugin/config';
|
||||
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 {
|
||||
type EndpointSuggestionsBody,
|
||||
EndpointSuggestionsSchema,
|
||||
|
@ -71,11 +70,6 @@ export const getEndpointSuggestionsRequestHandler = (
|
|||
let index = '';
|
||||
|
||||
if (request.params.suggestion_type === 'eventFilters') {
|
||||
if (!EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS.includes(fieldName)) {
|
||||
return response.badRequest({
|
||||
body: `Unsupported field name: ${fieldName}`,
|
||||
});
|
||||
}
|
||||
index = eventsIndexPattern;
|
||||
} else {
|
||||
return response.badRequest({
|
||||
|
|
|
@ -13,25 +13,18 @@ import type {
|
|||
CreateExceptionListItemOptions,
|
||||
UpdateExceptionListItemOptions,
|
||||
} from '@kbn/lists-plugin/server';
|
||||
import { EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS } from '../../../../common/endpoint/exceptions/exceptionable_endpoint_event_fields';
|
||||
|
||||
import type { ExceptionItemLikeOptions } from '../types';
|
||||
|
||||
import { BaseValidator } from './base_validator';
|
||||
import { EndpointArtifactExceptionValidationError } from './errors';
|
||||
|
||||
function validateField(field: string) {
|
||||
if (!EXCEPTIONABLE_ENDPOINT_EVENT_FIELDS.includes(field)) {
|
||||
return `invalid field: ${field}`;
|
||||
}
|
||||
}
|
||||
|
||||
const EventFilterDataSchema = schema.object(
|
||||
{
|
||||
entries: schema.arrayOf(
|
||||
schema.object(
|
||||
{
|
||||
field: schema.string({ validate: validateField }),
|
||||
field: schema.string(),
|
||||
},
|
||||
{ unknowns: 'ignore' }
|
||||
),
|
||||
|
|
|
@ -207,21 +207,22 @@ export const getArtifactsListTestsData = () => [
|
|||
},
|
||||
{
|
||||
type: 'customClick',
|
||||
selector: 'button[title="agent.type"]',
|
||||
selector: 'button[title="agent.ephemeral_id"]',
|
||||
},
|
||||
{
|
||||
type: 'click',
|
||||
selector: 'valuesAutocompleteMatch',
|
||||
},
|
||||
{
|
||||
type: 'customClick',
|
||||
selector: 'button[title="endpoint"]',
|
||||
type: 'input',
|
||||
selector: 'valuesAutocompleteMatch',
|
||||
value: 'endpoint',
|
||||
},
|
||||
],
|
||||
checkResults: [
|
||||
{
|
||||
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',
|
||||
selector: 'button[title="agent.name"]',
|
||||
selector: 'button[title="agent.id"]',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
|
@ -258,7 +259,7 @@ export const getArtifactsListTestsData = () => [
|
|||
checkResults: [
|
||||
{
|
||||
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',
|
||||
|
@ -269,7 +270,7 @@ export const getArtifactsListTestsData = () => [
|
|||
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: {
|
||||
confirmSelector: 'EventFiltersListPage-deleteModal-submitButton',
|
||||
|
@ -283,17 +284,17 @@ export const getArtifactsListTestsData = () => [
|
|||
getExpectedUpdatedtArtifactWhenCreate: (): ArtifactElasticsearchProperties => ({
|
||||
type: 'eventfilterlist',
|
||||
identifier: 'endpoint-eventfilterlist-windows-v1',
|
||||
body: 'eJxVzFEKgCAQBNC77Ld0AK8SEYtusWAqukYh3b1F+on5ezNMB4pSmCrYuYPcmcBC5SMHAvPrNqbgtcRddRpLAylTQUlFnaMLzZNX/W7oQierwzrwxNCGRp8TR4Fn0bwiRSx6',
|
||||
body: 'eJxVjEEKwzAMBP+ic+kD8pUSgrA3qUCxha2EltC/Vwm9lL0sM8sehOJN0Gl4HORvAw3UZTUF3f7cLNAckpegd9gTKxrrJDmG1aJ7beGlJN0yTvq7w4uTT4n7BXfW7aIlW5Xi9BkjX6sIL5c=',
|
||||
package_name: 'endpoint',
|
||||
created: '2000-01-01T00:00:00.000Z',
|
||||
relative_url:
|
||||
'/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/54e692d3d896a72ba8b0ccc1e174d9c24d43e427ea88a42ddba8ec0839a37fec',
|
||||
'/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/b3373c93ffc795d954f22c625c084dc5874a156ec0cb3d4af1c3dab0b965fa30',
|
||||
compression_algorithm: 'zlib',
|
||||
decoded_size: 128,
|
||||
decoded_sha256: '54e692d3d896a72ba8b0ccc1e174d9c24d43e427ea88a42ddba8ec0839a37fec',
|
||||
decoded_size: 136,
|
||||
decoded_sha256: 'b3373c93ffc795d954f22c625c084dc5874a156ec0cb3d4af1c3dab0b965fa30',
|
||||
encryption_algorithm: 'none',
|
||||
encoded_sha256: '3f3f689efc895ada36b232b71d63f93b9b9552f84d395689f828429017016b46',
|
||||
encoded_size: 99,
|
||||
encoded_sha256: 'c1b30df9457ba007065fff1388c026ad269e63fbed535b506ac559fd616aabe9',
|
||||
encoded_size: 107,
|
||||
}),
|
||||
getExpectedUpdatedArtifactBodyWhenCreate: (): ArtifactBodyType => ({
|
||||
entries: [
|
||||
|
@ -301,7 +302,7 @@ export const getArtifactsListTestsData = () => [
|
|||
type: 'simple',
|
||||
entries: [
|
||||
{
|
||||
field: 'agent.type',
|
||||
field: 'agent.ephemeral_id',
|
||||
operator: 'included',
|
||||
type: 'exact_cased',
|
||||
value: 'endpoint',
|
||||
|
@ -313,17 +314,17 @@ export const getArtifactsListTestsData = () => [
|
|||
getExpectedUpdatedArtifactWhenUpdate: (): ArtifactElasticsearchProperties => ({
|
||||
type: 'eventfilterlist',
|
||||
identifier: 'endpoint-eventfilterlist-windows-v1',
|
||||
body: 'eJxVjFEKgzAQRK8S9rt4AK8ipSzJKIE1huxGWsS7u9L+lPl7b2YOQrGWoTROB9mngkbSvFYBPf7cnCHJJS9Oh8LrXdgqGtvWnOcSpSckp78bvDnaK7JCoOp8Z+m3MKgF7b4Nwm1B+Irz6bkASPAywg==',
|
||||
body: 'eJxVzEEKwkAMheGrDFmLB+hVikiYeS2B2A6TjCildze1biS77+dlIyzeBEbDuJG/K2ggk0dV0OWvTQItEXkOvUqJvFY09rWFypK1Fxz6e4IXZ79nti8+WfuhDvNkPYZJuc1IZ9hvcR86lDCb',
|
||||
package_name: 'endpoint',
|
||||
created: '2000-01-01T00:00:00.000Z',
|
||||
relative_url:
|
||||
'/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/49b7181f97ea4c92dd8457cabb6d67bde7e05d02a7f41ce8ae40ff2e5819e098',
|
||||
'/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/e4f00c88380d2c429eeb2741ad19383b94d76f79744b098b095befc24003e158',
|
||||
compression_algorithm: 'zlib',
|
||||
decoded_size: 145,
|
||||
decoded_sha256: '49b7181f97ea4c92dd8457cabb6d67bde7e05d02a7f41ce8ae40ff2e5819e098',
|
||||
decoded_size: 140,
|
||||
decoded_sha256: 'e4f00c88380d2c429eeb2741ad19383b94d76f79744b098b095befc24003e158',
|
||||
encryption_algorithm: 'none',
|
||||
encoded_sha256: 'f852031403be242a4190b9c5ea2726706877bb0d45fe9b21f8b297ed11ab1d7c',
|
||||
encoded_size: 112,
|
||||
encoded_sha256: '99386e3d9a67eac88f0a4cc4ac36ad42cfda42598ce0ee1c11a8afc50bf004fe',
|
||||
encoded_size: 108,
|
||||
}),
|
||||
getExpectedUpdatedArtifactBodyWhenUpdate: (): ArtifactBodyType => ({
|
||||
entries: [
|
||||
|
@ -331,9 +332,9 @@ export const getArtifactsListTestsData = () => [
|
|||
type: 'simple',
|
||||
entries: [
|
||||
{
|
||||
field: 'agent.name',
|
||||
field: 'agent.id',
|
||||
operator: 'included',
|
||||
type: 'exact_caseless',
|
||||
type: 'exact_cased',
|
||||
value: 'test super large value',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -178,20 +178,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
describe('and has authorization to manage endpoint security', () => {
|
||||
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 () => {
|
||||
const body = eventFilterApiCall.getBody({ os_types: ['linux', 'windows'] });
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue