Skip to content

Commit c456f64

Browse files
[Security Solution][Exceptions] Add lowercase normalizer for case-insensitivity + deprecate _tags field (new OS field) (#77379)
* Finish adding .lower to exceptionable fields * Add back migrations * .lower -> .caseless * Add separate field for os type * updates * Type updates * Switch over to osTypes * get rid of _tags * Add tests for schema validation * Remove remaining references to _tags * Another round of test fixes * DefaultArray tests * More test fixes * Fix remaining test failures * types / tests * more test updates * lowercase os values * Address feedback + fix test failure * tests * Fix integration test * process.executable.path -> process.executable.caseless Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
1 parent b66de2c commit c456f64

File tree

92 files changed

+636
-479
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+636
-479
lines changed

x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,37 @@ test('tests processing keyword field with multi fields with analyzed text field'
212212
expect(mappings).toEqual(keywordWithAnalyzedMultiFieldsMapping);
213213
});
214214

215+
test('tests processing keyword field with multi fields with normalized keyword field', () => {
216+
const keywordWithNormalizedMultiFieldsLiteralYml = `
217+
- name: keywordWithNormalizedMultiField
218+
type: keyword
219+
multi_fields:
220+
- name: normalized
221+
type: keyword
222+
normalizer: lowercase
223+
`;
224+
225+
const keywordWithNormalizedMultiFieldsMapping = {
226+
properties: {
227+
keywordWithNormalizedMultiField: {
228+
ignore_above: 1024,
229+
type: 'keyword',
230+
fields: {
231+
normalized: {
232+
type: 'keyword',
233+
ignore_above: 1024,
234+
normalizer: 'lowercase',
235+
},
236+
},
237+
},
238+
},
239+
};
240+
const fields: Field[] = safeLoad(keywordWithNormalizedMultiFieldsLiteralYml);
241+
const processedFields = processFields(fields);
242+
const mappings = generateMappings(processedFields);
243+
expect(mappings).toEqual(keywordWithNormalizedMultiFieldsMapping);
244+
});
245+
215246
test('tests processing object field with no other attributes', () => {
216247
const objectFieldLiteralYml = `
217248
- name: objectField

x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ function generateKeywordMapping(field: Field): IndexTemplateMapping {
189189
if (field.ignore_above) {
190190
mapping.ignore_above = field.ignore_above;
191191
}
192+
if (field.normalizer) {
193+
mapping.normalizer = field.normalizer;
194+
}
192195
return mapping;
193196
}
194197

x-pack/plugins/ingest_manager/server/services/epm/fields/field.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface Field {
2020
index?: boolean;
2121
required?: boolean;
2222
multi_fields?: Fields;
23+
normalizer?: string;
2324
doc_values?: boolean;
2425
copy_to?: string;
2526
analyzer?: string;

x-pack/plugins/lists/README.md

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,6 @@ You should see the new exception list created like so:
113113

114114
```sh
115115
{
116-
"_tags": [
117-
"endpoint",
118-
"process",
119-
"malware",
120-
"os:linux"
121-
],
122116
"created_at": "2020-05-28T19:16:31.052Z",
123117
"created_by": "yo",
124118
"description": "This is a sample endpoint type exception",
@@ -141,12 +135,6 @@ And you can attach exception list items like so:
141135

142136
```ts
143137
{
144-
"_tags": [
145-
"endpoint",
146-
"process",
147-
"malware",
148-
"os:linux"
149-
],
150138
"comments": [],
151139
"created_at": "2020-05-28T19:17:21.099Z",
152140
"created_by": "yo",
@@ -173,6 +161,7 @@ And you can attach exception list items like so:
173161
"list_id": "endpoint_list",
174162
"name": "Sample Endpoint Exception List",
175163
"namespace_type": "single",
164+
"os_types": ["linux"],
176165
"tags": [
177166
"user added string for a tag",
178167
"malware"
@@ -222,19 +211,14 @@ or for finding exception lists:
222211
{
223212
"data": [
224213
{
225-
"_tags": [
226-
"endpoint",
227-
"process",
228-
"malware",
229-
"os:linux"
230-
],
231214
"created_at": "2020-05-28T19:16:31.052Z",
232215
"created_by": "yo",
233216
"description": "This is a sample endpoint type exception",
234217
"id": "bcb94680-a117-11ea-ad9d-c71f4820e65b",
235218
"list_id": "endpoint_list",
236219
"name": "Sample Endpoint Exception List",
237220
"namespace_type": "single",
221+
"os_types": ["linux"],
238222
"tags": [
239223
"user added string for a tag",
240224
"malware"

x-pack/plugins/lists/common/constants.mock.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
import moment from 'moment';
77

8+
import { OsTypeArray } from './schemas/common';
89
import { EntriesArray } from './schemas/types';
910
import { EndpointEntriesArray } from './schemas/types/endpoint';
1011
export const DATE_NOW = '2020-04-20T15:25:31.830Z';
@@ -68,7 +69,7 @@ export const ENDPOINT_ENTRIES: EndpointEntriesArray = [
6869
{ field: 'some.not.nested.field', operator: 'included', type: 'match', value: 'some value' },
6970
];
7071
export const ITEM_TYPE = 'simple';
71-
export const _TAGS = [];
72+
export const OS_TYPES: OsTypeArray = ['windows'];
7273
export const TAGS = [];
7374
export const COMMENTS = [];
7475
export const FILTER = 'name:Nicolas Bourbaki';

x-pack/plugins/lists/common/schemas/common/schemas.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import {
2727
esDataTypeUnion,
2828
exceptionListType,
2929
operator,
30+
osType,
31+
osTypeArrayOrUndefined,
3032
type,
3133
} from './schemas';
3234

@@ -379,4 +381,35 @@ describe('Common schemas', () => {
379381
expect(message.schema).toEqual({});
380382
});
381383
});
384+
385+
describe('osType', () => {
386+
test('it will validate a correct osType', () => {
387+
const payload = 'windows';
388+
const decoded = osType.decode(payload);
389+
const checked = exactCheck(payload, decoded);
390+
const message = pipe(checked, foldLeftRight);
391+
expect(getPaths(left(message.errors))).toEqual([]);
392+
expect(message.schema).toEqual(payload);
393+
});
394+
395+
test('it will fail to validate an incorrect osType', () => {
396+
const payload = 'foo';
397+
const decoded = osType.decode(payload);
398+
const checked = exactCheck(payload, decoded);
399+
const message = pipe(checked, foldLeftRight);
400+
expect(getPaths(left(message.errors))).toEqual([
401+
'Invalid value "foo" supplied to ""linux" | "macos" | "windows""',
402+
]);
403+
expect(message.schema).toEqual({});
404+
});
405+
406+
test('it will default to an empty array when osTypeArrayOrUndefined is used', () => {
407+
const payload = undefined;
408+
const decoded = osTypeArrayOrUndefined.decode(payload);
409+
const checked = exactCheck(payload, decoded);
410+
const message = pipe(checked, foldLeftRight);
411+
expect(getPaths(left(message.errors))).toEqual([]);
412+
expect(message.schema).toEqual([]);
413+
});
414+
});
382415
});

x-pack/plugins/lists/common/schemas/common/schemas.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import * as t from 'io-ts';
1010

1111
import { DefaultNamespace } from '../types/default_namespace';
12-
import { DefaultStringArray, NonEmptyString } from '../../shared_imports';
12+
import { DefaultArray, DefaultStringArray, NonEmptyString } from '../../shared_imports';
1313

1414
export const name = t.string;
1515
export type Name = t.TypeOf<typeof name>;
@@ -211,11 +211,6 @@ export type Tags = t.TypeOf<typeof tags>;
211211
export const tagsOrUndefined = t.union([tags, t.undefined]);
212212
export type TagsOrUndefined = t.TypeOf<typeof tagsOrUndefined>;
213213

214-
export const _tags = DefaultStringArray;
215-
export type _Tags = t.TypeOf<typeof _tags>;
216-
export const _tagsOrUndefined = t.union([_tags, t.undefined]);
217-
export type _TagsOrUndefined = t.TypeOf<typeof _tagsOrUndefined>;
218-
219214
export const exceptionListType = t.keyof({ detection: null, endpoint: null });
220215
export const exceptionListTypeOrUndefined = t.union([exceptionListType, t.undefined]);
221216
export type ExceptionListType = t.TypeOf<typeof exceptionListType>;
@@ -317,3 +312,16 @@ export type Immutable = t.TypeOf<typeof immutable>;
317312

318313
export const immutableOrUndefined = t.union([immutable, t.undefined]);
319314
export type ImmutableOrUndefined = t.TypeOf<typeof immutableOrUndefined>;
315+
316+
export const osType = t.keyof({
317+
linux: null,
318+
macos: null,
319+
windows: null,
320+
});
321+
export type OsType = t.TypeOf<typeof osType>;
322+
323+
export const osTypeArray = DefaultArray(osType);
324+
export type OsTypeArray = t.TypeOf<typeof osTypeArray>;
325+
326+
export const osTypeArrayOrUndefined = t.union([osTypeArray, t.undefined]);
327+
export type OsTypeArrayOrUndefined = t.OutputOf<typeof osTypeArray>;

x-pack/plugins/lists/common/schemas/request/create_endpoint_list_item_schema.mock.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ import {
1111
ITEM_TYPE,
1212
META,
1313
NAME,
14+
OS_TYPES,
1415
TAGS,
15-
_TAGS,
1616
} from '../../constants.mock';
1717

1818
import { CreateEndpointListItemSchema } from './create_endpoint_list_item_schema';
1919

2020
export const getCreateEndpointListItemSchemaMock = (): CreateEndpointListItemSchema => ({
21-
_tags: _TAGS,
2221
comments: COMMENTS,
2322
description: DESCRIPTION,
2423
entries: ENDPOINT_ENTRIES,
2524
item_id: undefined,
2625
meta: META,
2726
name: NAME,
27+
os_types: OS_TYPES,
2828
tags: TAGS,
2929
type: ITEM_TYPE,
3030
});

x-pack/plugins/lists/common/schemas/request/create_endpoint_list_item_schema.test.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -174,19 +174,6 @@ describe('create_endpoint_list_item_schema', () => {
174174
expect(message.schema).toEqual(outputPayload);
175175
});
176176

177-
test('it should pass validation when supplied an undefined for "_tags" but return an array and generate a correct body not counting the auto generated uuid', () => {
178-
const inputPayload = getCreateEndpointListItemSchemaMock();
179-
const outputPayload = getCreateEndpointListItemSchemaMock();
180-
delete inputPayload._tags;
181-
outputPayload._tags = [];
182-
const decoded = createEndpointListItemSchema.decode(inputPayload);
183-
const checked = exactCheck(inputPayload, decoded);
184-
const message = pipe(checked, foldLeftRight);
185-
delete (message.schema as CreateEndpointListItemSchema).item_id;
186-
expect(getPaths(left(message.errors))).toEqual([]);
187-
expect(message.schema).toEqual(outputPayload);
188-
});
189-
190177
test('it should pass validation when supplied an undefined for "item_id" and auto generate a uuid', () => {
191178
const inputPayload = getCreateEndpointListItemSchemaMock();
192179
delete inputPayload.item_id;

x-pack/plugins/lists/common/schemas/request/create_endpoint_list_item_schema.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ import * as t from 'io-ts';
88

99
import {
1010
ItemId,
11+
OsTypeArray,
1112
Tags,
12-
_Tags,
13-
_tags,
1413
description,
1514
exceptionListItemType,
1615
meta,
1716
name,
17+
osTypeArrayOrUndefined,
1818
tags,
1919
} from '../common/schemas';
2020
import { RequiredKeepUndefined } from '../../types';
@@ -34,10 +34,10 @@ export const createEndpointListItemSchema = t.intersection([
3434
),
3535
t.exact(
3636
t.partial({
37-
_tags, // defaults to empty array if not set during decode
3837
comments: DefaultCreateCommentsArray, // defaults to empty array if not set during decode
3938
item_id: DefaultUuid, // defaults to GUID (uuid v4) if not set during decode
4039
meta, // defaults to undefined if not set during decode
40+
os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode
4141
tags, // defaults to empty array if not set during decode
4242
})
4343
),
@@ -48,11 +48,11 @@ export type CreateEndpointListItemSchema = t.OutputOf<typeof createEndpointListI
4848
// This type is used after a decode since some things are defaults after a decode.
4949
export type CreateEndpointListItemSchemaDecoded = Omit<
5050
RequiredKeepUndefined<t.TypeOf<typeof createEndpointListItemSchema>>,
51-
'_tags' | 'tags' | 'item_id' | 'entries' | 'comments'
51+
'tags' | 'item_id' | 'entries' | 'comments' | 'os_types'
5252
> & {
53-
_tags: _Tags;
5453
comments: CreateCommentsArray;
5554
tags: Tags;
5655
item_id: ItemId;
5756
entries: EntriesArray;
57+
os_types: OsTypeArray;
5858
};

0 commit comments

Comments
 (0)