mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[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>
This commit is contained in:
parent
b66de2ce1d
commit
c456f64a7e
92 changed files with 636 additions and 479 deletions
|
@ -212,6 +212,37 @@ test('tests processing keyword field with multi fields with analyzed text field'
|
|||
expect(mappings).toEqual(keywordWithAnalyzedMultiFieldsMapping);
|
||||
});
|
||||
|
||||
test('tests processing keyword field with multi fields with normalized keyword field', () => {
|
||||
const keywordWithNormalizedMultiFieldsLiteralYml = `
|
||||
- name: keywordWithNormalizedMultiField
|
||||
type: keyword
|
||||
multi_fields:
|
||||
- name: normalized
|
||||
type: keyword
|
||||
normalizer: lowercase
|
||||
`;
|
||||
|
||||
const keywordWithNormalizedMultiFieldsMapping = {
|
||||
properties: {
|
||||
keywordWithNormalizedMultiField: {
|
||||
ignore_above: 1024,
|
||||
type: 'keyword',
|
||||
fields: {
|
||||
normalized: {
|
||||
type: 'keyword',
|
||||
ignore_above: 1024,
|
||||
normalizer: 'lowercase',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const fields: Field[] = safeLoad(keywordWithNormalizedMultiFieldsLiteralYml);
|
||||
const processedFields = processFields(fields);
|
||||
const mappings = generateMappings(processedFields);
|
||||
expect(mappings).toEqual(keywordWithNormalizedMultiFieldsMapping);
|
||||
});
|
||||
|
||||
test('tests processing object field with no other attributes', () => {
|
||||
const objectFieldLiteralYml = `
|
||||
- name: objectField
|
||||
|
|
|
@ -189,6 +189,9 @@ function generateKeywordMapping(field: Field): IndexTemplateMapping {
|
|||
if (field.ignore_above) {
|
||||
mapping.ignore_above = field.ignore_above;
|
||||
}
|
||||
if (field.normalizer) {
|
||||
mapping.normalizer = field.normalizer;
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ export interface Field {
|
|||
index?: boolean;
|
||||
required?: boolean;
|
||||
multi_fields?: Fields;
|
||||
normalizer?: string;
|
||||
doc_values?: boolean;
|
||||
copy_to?: string;
|
||||
analyzer?: string;
|
||||
|
|
|
@ -113,12 +113,6 @@ You should see the new exception list created like so:
|
|||
|
||||
```sh
|
||||
{
|
||||
"_tags": [
|
||||
"endpoint",
|
||||
"process",
|
||||
"malware",
|
||||
"os:linux"
|
||||
],
|
||||
"created_at": "2020-05-28T19:16:31.052Z",
|
||||
"created_by": "yo",
|
||||
"description": "This is a sample endpoint type exception",
|
||||
|
@ -141,12 +135,6 @@ And you can attach exception list items like so:
|
|||
|
||||
```ts
|
||||
{
|
||||
"_tags": [
|
||||
"endpoint",
|
||||
"process",
|
||||
"malware",
|
||||
"os:linux"
|
||||
],
|
||||
"comments": [],
|
||||
"created_at": "2020-05-28T19:17:21.099Z",
|
||||
"created_by": "yo",
|
||||
|
@ -173,6 +161,7 @@ And you can attach exception list items like so:
|
|||
"list_id": "endpoint_list",
|
||||
"name": "Sample Endpoint Exception List",
|
||||
"namespace_type": "single",
|
||||
"os_types": ["linux"],
|
||||
"tags": [
|
||||
"user added string for a tag",
|
||||
"malware"
|
||||
|
@ -222,12 +211,6 @@ or for finding exception lists:
|
|||
{
|
||||
"data": [
|
||||
{
|
||||
"_tags": [
|
||||
"endpoint",
|
||||
"process",
|
||||
"malware",
|
||||
"os:linux"
|
||||
],
|
||||
"created_at": "2020-05-28T19:16:31.052Z",
|
||||
"created_by": "yo",
|
||||
"description": "This is a sample endpoint type exception",
|
||||
|
@ -235,6 +218,7 @@ or for finding exception lists:
|
|||
"list_id": "endpoint_list",
|
||||
"name": "Sample Endpoint Exception List",
|
||||
"namespace_type": "single",
|
||||
"os_types": ["linux"],
|
||||
"tags": [
|
||||
"user added string for a tag",
|
||||
"malware"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
import moment from 'moment';
|
||||
|
||||
import { OsTypeArray } from './schemas/common';
|
||||
import { EntriesArray } from './schemas/types';
|
||||
import { EndpointEntriesArray } from './schemas/types/endpoint';
|
||||
export const DATE_NOW = '2020-04-20T15:25:31.830Z';
|
||||
|
@ -68,7 +69,7 @@ export const ENDPOINT_ENTRIES: EndpointEntriesArray = [
|
|||
{ field: 'some.not.nested.field', operator: 'included', type: 'match', value: 'some value' },
|
||||
];
|
||||
export const ITEM_TYPE = 'simple';
|
||||
export const _TAGS = [];
|
||||
export const OS_TYPES: OsTypeArray = ['windows'];
|
||||
export const TAGS = [];
|
||||
export const COMMENTS = [];
|
||||
export const FILTER = 'name:Nicolas Bourbaki';
|
||||
|
|
|
@ -27,6 +27,8 @@ import {
|
|||
esDataTypeUnion,
|
||||
exceptionListType,
|
||||
operator,
|
||||
osType,
|
||||
osTypeArrayOrUndefined,
|
||||
type,
|
||||
} from './schemas';
|
||||
|
||||
|
@ -379,4 +381,35 @@ describe('Common schemas', () => {
|
|||
expect(message.schema).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('osType', () => {
|
||||
test('it will validate a correct osType', () => {
|
||||
const payload = 'windows';
|
||||
const decoded = osType.decode(payload);
|
||||
const checked = exactCheck(payload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
expect(message.schema).toEqual(payload);
|
||||
});
|
||||
|
||||
test('it will fail to validate an incorrect osType', () => {
|
||||
const payload = 'foo';
|
||||
const decoded = osType.decode(payload);
|
||||
const checked = exactCheck(payload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
expect(getPaths(left(message.errors))).toEqual([
|
||||
'Invalid value "foo" supplied to ""linux" | "macos" | "windows""',
|
||||
]);
|
||||
expect(message.schema).toEqual({});
|
||||
});
|
||||
|
||||
test('it will default to an empty array when osTypeArrayOrUndefined is used', () => {
|
||||
const payload = undefined;
|
||||
const decoded = osTypeArrayOrUndefined.decode(payload);
|
||||
const checked = exactCheck(payload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
expect(message.schema).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import { DefaultNamespace } from '../types/default_namespace';
|
||||
import { DefaultStringArray, NonEmptyString } from '../../shared_imports';
|
||||
import { DefaultArray, DefaultStringArray, NonEmptyString } from '../../shared_imports';
|
||||
|
||||
export const name = t.string;
|
||||
export type Name = t.TypeOf<typeof name>;
|
||||
|
@ -211,11 +211,6 @@ export type Tags = t.TypeOf<typeof tags>;
|
|||
export const tagsOrUndefined = t.union([tags, t.undefined]);
|
||||
export type TagsOrUndefined = t.TypeOf<typeof tagsOrUndefined>;
|
||||
|
||||
export const _tags = DefaultStringArray;
|
||||
export type _Tags = t.TypeOf<typeof _tags>;
|
||||
export const _tagsOrUndefined = t.union([_tags, t.undefined]);
|
||||
export type _TagsOrUndefined = t.TypeOf<typeof _tagsOrUndefined>;
|
||||
|
||||
export const exceptionListType = t.keyof({ detection: null, endpoint: null });
|
||||
export const exceptionListTypeOrUndefined = t.union([exceptionListType, t.undefined]);
|
||||
export type ExceptionListType = t.TypeOf<typeof exceptionListType>;
|
||||
|
@ -317,3 +312,16 @@ export type Immutable = t.TypeOf<typeof immutable>;
|
|||
|
||||
export const immutableOrUndefined = t.union([immutable, t.undefined]);
|
||||
export type ImmutableOrUndefined = t.TypeOf<typeof immutableOrUndefined>;
|
||||
|
||||
export const osType = t.keyof({
|
||||
linux: null,
|
||||
macos: null,
|
||||
windows: null,
|
||||
});
|
||||
export type OsType = t.TypeOf<typeof osType>;
|
||||
|
||||
export const osTypeArray = DefaultArray(osType);
|
||||
export type OsTypeArray = t.TypeOf<typeof osTypeArray>;
|
||||
|
||||
export const osTypeArrayOrUndefined = t.union([osTypeArray, t.undefined]);
|
||||
export type OsTypeArrayOrUndefined = t.OutputOf<typeof osTypeArray>;
|
||||
|
|
|
@ -11,20 +11,20 @@ import {
|
|||
ITEM_TYPE,
|
||||
META,
|
||||
NAME,
|
||||
OS_TYPES,
|
||||
TAGS,
|
||||
_TAGS,
|
||||
} from '../../constants.mock';
|
||||
|
||||
import { CreateEndpointListItemSchema } from './create_endpoint_list_item_schema';
|
||||
|
||||
export const getCreateEndpointListItemSchemaMock = (): CreateEndpointListItemSchema => ({
|
||||
_tags: _TAGS,
|
||||
comments: COMMENTS,
|
||||
description: DESCRIPTION,
|
||||
entries: ENDPOINT_ENTRIES,
|
||||
item_id: undefined,
|
||||
meta: META,
|
||||
name: NAME,
|
||||
os_types: OS_TYPES,
|
||||
tags: TAGS,
|
||||
type: ITEM_TYPE,
|
||||
});
|
||||
|
|
|
@ -174,19 +174,6 @@ describe('create_endpoint_list_item_schema', () => {
|
|||
expect(message.schema).toEqual(outputPayload);
|
||||
});
|
||||
|
||||
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', () => {
|
||||
const inputPayload = getCreateEndpointListItemSchemaMock();
|
||||
const outputPayload = getCreateEndpointListItemSchemaMock();
|
||||
delete inputPayload._tags;
|
||||
outputPayload._tags = [];
|
||||
const decoded = createEndpointListItemSchema.decode(inputPayload);
|
||||
const checked = exactCheck(inputPayload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
delete (message.schema as CreateEndpointListItemSchema).item_id;
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
expect(message.schema).toEqual(outputPayload);
|
||||
});
|
||||
|
||||
test('it should pass validation when supplied an undefined for "item_id" and auto generate a uuid', () => {
|
||||
const inputPayload = getCreateEndpointListItemSchemaMock();
|
||||
delete inputPayload.item_id;
|
||||
|
|
|
@ -8,13 +8,13 @@ import * as t from 'io-ts';
|
|||
|
||||
import {
|
||||
ItemId,
|
||||
OsTypeArray,
|
||||
Tags,
|
||||
_Tags,
|
||||
_tags,
|
||||
description,
|
||||
exceptionListItemType,
|
||||
meta,
|
||||
name,
|
||||
osTypeArrayOrUndefined,
|
||||
tags,
|
||||
} from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
@ -34,10 +34,10 @@ export const createEndpointListItemSchema = t.intersection([
|
|||
),
|
||||
t.exact(
|
||||
t.partial({
|
||||
_tags, // defaults to empty array if not set during decode
|
||||
comments: DefaultCreateCommentsArray, // defaults to empty array if not set during decode
|
||||
item_id: DefaultUuid, // defaults to GUID (uuid v4) if not set during decode
|
||||
meta, // defaults to undefined if not set during decode
|
||||
os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode
|
||||
tags, // defaults to empty array if not set during decode
|
||||
})
|
||||
),
|
||||
|
@ -48,11 +48,11 @@ export type CreateEndpointListItemSchema = t.OutputOf<typeof createEndpointListI
|
|||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type CreateEndpointListItemSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof createEndpointListItemSchema>>,
|
||||
'_tags' | 'tags' | 'item_id' | 'entries' | 'comments'
|
||||
'tags' | 'item_id' | 'entries' | 'comments' | 'os_types'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
comments: CreateCommentsArray;
|
||||
tags: Tags;
|
||||
item_id: ItemId;
|
||||
entries: EntriesArray;
|
||||
os_types: OsTypeArray;
|
||||
};
|
||||
|
|
|
@ -14,14 +14,13 @@ import {
|
|||
META,
|
||||
NAME,
|
||||
NAMESPACE_TYPE,
|
||||
OS_TYPES,
|
||||
TAGS,
|
||||
_TAGS,
|
||||
} from '../../constants.mock';
|
||||
|
||||
import { CreateExceptionListItemSchema } from './create_exception_list_item_schema';
|
||||
|
||||
export const getCreateExceptionListItemSchemaMock = (): CreateExceptionListItemSchema => ({
|
||||
_tags: _TAGS,
|
||||
comments: COMMENTS,
|
||||
description: DESCRIPTION,
|
||||
entries: ENTRIES,
|
||||
|
@ -30,6 +29,7 @@ export const getCreateExceptionListItemSchemaMock = (): CreateExceptionListItemS
|
|||
meta: META,
|
||||
name: NAME,
|
||||
namespace_type: NAMESPACE_TYPE,
|
||||
os_types: OS_TYPES,
|
||||
tags: TAGS,
|
||||
type: ITEM_TYPE,
|
||||
});
|
||||
|
@ -43,6 +43,7 @@ export const getCreateExceptionListItemMinimalSchemaMock = (): CreateExceptionLi
|
|||
item_id: ITEM_ID,
|
||||
list_id: LIST_ID,
|
||||
name: NAME,
|
||||
os_types: OS_TYPES,
|
||||
type: ITEM_TYPE,
|
||||
});
|
||||
|
||||
|
@ -54,5 +55,6 @@ export const getCreateExceptionListItemMinimalSchemaMockWithoutId = (): CreateEx
|
|||
entries: ENTRIES,
|
||||
list_id: LIST_ID,
|
||||
name: NAME,
|
||||
os_types: OS_TYPES,
|
||||
type: ITEM_TYPE,
|
||||
});
|
||||
|
|
|
@ -176,19 +176,6 @@ describe('create_exception_list_item_schema', () => {
|
|||
expect(message.schema).toEqual(outputPayload);
|
||||
});
|
||||
|
||||
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', () => {
|
||||
const inputPayload = getCreateExceptionListItemSchemaMock();
|
||||
const outputPayload = getCreateExceptionListItemSchemaMock();
|
||||
delete inputPayload._tags;
|
||||
outputPayload._tags = [];
|
||||
const decoded = createExceptionListItemSchema.decode(inputPayload);
|
||||
const checked = exactCheck(inputPayload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
delete (message.schema as CreateExceptionListItemSchema).item_id;
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
expect(message.schema).toEqual(outputPayload);
|
||||
});
|
||||
|
||||
test('it should pass validation when supplied an undefined for "item_id" and auto generate a uuid', () => {
|
||||
const inputPayload = getCreateExceptionListItemSchemaMock();
|
||||
delete inputPayload.item_id;
|
||||
|
|
|
@ -8,15 +8,15 @@ import * as t from 'io-ts';
|
|||
|
||||
import {
|
||||
ItemId,
|
||||
OsTypeArray,
|
||||
Tags,
|
||||
_Tags,
|
||||
_tags,
|
||||
description,
|
||||
exceptionListItemType,
|
||||
list_id,
|
||||
meta,
|
||||
name,
|
||||
namespace_type,
|
||||
osTypeArrayOrUndefined,
|
||||
tags,
|
||||
} from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
@ -41,11 +41,11 @@ export const createExceptionListItemSchema = t.intersection([
|
|||
),
|
||||
t.exact(
|
||||
t.partial({
|
||||
_tags, // defaults to empty array if not set during decode
|
||||
comments: DefaultCreateCommentsArray, // defaults to empty array if not set during decode
|
||||
item_id: DefaultUuid, // defaults to GUID (uuid v4) if not set during decode
|
||||
meta, // defaults to undefined if not set during decode
|
||||
namespace_type, // defaults to 'single' if not set during decode
|
||||
os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode
|
||||
tags, // defaults to empty array if not set during decode
|
||||
})
|
||||
),
|
||||
|
@ -56,12 +56,12 @@ export type CreateExceptionListItemSchema = t.OutputOf<typeof createExceptionLis
|
|||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type CreateExceptionListItemSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof createExceptionListItemSchema>>,
|
||||
'_tags' | 'tags' | 'item_id' | 'entries' | 'namespace_type' | 'comments'
|
||||
'tags' | 'item_id' | 'entries' | 'namespace_type' | 'comments'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
comments: CreateCommentsArray;
|
||||
tags: Tags;
|
||||
item_id: ItemId;
|
||||
entries: EntriesArray;
|
||||
namespace_type: NamespaceType;
|
||||
os_types: OsTypeArray;
|
||||
};
|
||||
|
|
|
@ -17,12 +17,12 @@ import {
|
|||
import { CreateExceptionListSchema } from './create_exception_list_schema';
|
||||
|
||||
export const getCreateExceptionListSchemaMock = (): CreateExceptionListSchema => ({
|
||||
_tags: [],
|
||||
description: DESCRIPTION,
|
||||
list_id: undefined,
|
||||
meta: META,
|
||||
name: NAME,
|
||||
namespace_type: NAMESPACE_TYPE,
|
||||
os_types: [],
|
||||
tags: [],
|
||||
type: ENDPOINT_TYPE,
|
||||
version: VERSION,
|
||||
|
|
|
@ -50,19 +50,6 @@ describe('create_exception_list_schema', () => {
|
|||
expect(message.schema).toEqual(outputPayload);
|
||||
});
|
||||
|
||||
test('it should accept an undefined for "_tags" but return an array and generate a correct body not counting the uuid', () => {
|
||||
const inputPayload = getCreateExceptionListSchemaMock();
|
||||
const outputPayload = getCreateExceptionListSchemaMock();
|
||||
delete inputPayload._tags;
|
||||
outputPayload._tags = [];
|
||||
const decoded = createExceptionListSchema.decode(inputPayload);
|
||||
const checked = exactCheck(inputPayload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
delete (message.schema as CreateExceptionListSchema).list_id;
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
expect(message.schema).toEqual(outputPayload);
|
||||
});
|
||||
|
||||
test('it should accept an undefined for "list_id" and auto generate a uuid', () => {
|
||||
const inputPayload = getCreateExceptionListSchemaMock();
|
||||
delete inputPayload.list_id;
|
||||
|
|
|
@ -8,14 +8,14 @@ import * as t from 'io-ts';
|
|||
|
||||
import {
|
||||
ListId,
|
||||
OsTypeArray,
|
||||
Tags,
|
||||
_Tags,
|
||||
_tags,
|
||||
description,
|
||||
exceptionListType,
|
||||
meta,
|
||||
name,
|
||||
namespace_type,
|
||||
osTypeArrayOrUndefined,
|
||||
tags,
|
||||
} from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
@ -36,10 +36,10 @@ export const createExceptionListSchema = t.intersection([
|
|||
),
|
||||
t.exact(
|
||||
t.partial({
|
||||
_tags, // defaults to empty array if not set during decode
|
||||
list_id: DefaultUuid, // defaults to a GUID (UUID v4) string if not set during decode
|
||||
meta, // defaults to undefined if not set during decode
|
||||
namespace_type, // defaults to 'single' if not set during decode
|
||||
os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode
|
||||
tags, // defaults to empty array if not set during decode
|
||||
version: DefaultVersionNumber, // defaults to numerical 1 if not set during decode
|
||||
})
|
||||
|
@ -51,11 +51,11 @@ export type CreateExceptionListSchema = t.OutputOf<typeof createExceptionListSch
|
|||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type CreateExceptionListSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof createExceptionListSchema>>,
|
||||
'_tags' | 'tags' | 'list_id' | 'namespace_type'
|
||||
'tags' | 'list_id' | 'namespace_type' | 'os_types'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
tags: Tags;
|
||||
list_id: ListId;
|
||||
namespace_type: NamespaceType;
|
||||
os_types: OsTypeArray;
|
||||
version: DefaultVersionNumberDecoded;
|
||||
};
|
||||
|
|
|
@ -13,14 +13,13 @@ import {
|
|||
LIST_ITEM_ID,
|
||||
META,
|
||||
NAME,
|
||||
OS_TYPES,
|
||||
TAGS,
|
||||
_TAGS,
|
||||
} from '../../constants.mock';
|
||||
|
||||
import { UpdateEndpointListItemSchema } from './update_endpoint_list_item_schema';
|
||||
|
||||
export const getUpdateEndpointListItemSchemaMock = (): UpdateEndpointListItemSchema => ({
|
||||
_tags: _TAGS,
|
||||
_version: undefined,
|
||||
comments: COMMENTS,
|
||||
description: DESCRIPTION,
|
||||
|
@ -29,6 +28,7 @@ export const getUpdateEndpointListItemSchemaMock = (): UpdateEndpointListItemSch
|
|||
item_id: LIST_ITEM_ID,
|
||||
meta: META,
|
||||
name: NAME,
|
||||
os_types: OS_TYPES,
|
||||
tags: TAGS,
|
||||
type: ITEM_TYPE,
|
||||
});
|
||||
|
|
|
@ -127,18 +127,6 @@ describe('update_endpoint_list_item_schema', () => {
|
|||
expect(message.schema).toEqual(outputPayload);
|
||||
});
|
||||
|
||||
test('it should accept an undefined for "_tags" but return an array', () => {
|
||||
const inputPayload = getUpdateEndpointListItemSchemaMock();
|
||||
const outputPayload = getUpdateEndpointListItemSchemaMock();
|
||||
delete inputPayload._tags;
|
||||
outputPayload._tags = [];
|
||||
const decoded = updateEndpointListItemSchema.decode(inputPayload);
|
||||
const checked = exactCheck(inputPayload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
expect(message.schema).toEqual(outputPayload);
|
||||
});
|
||||
|
||||
test('it should not allow an extra key to be sent in', () => {
|
||||
const payload: UpdateEndpointListItemSchema & {
|
||||
extraKey?: string;
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import {
|
||||
OsTypeArray,
|
||||
Tags,
|
||||
_Tags,
|
||||
_tags,
|
||||
_version,
|
||||
description,
|
||||
exceptionListItemType,
|
||||
id,
|
||||
meta,
|
||||
name,
|
||||
osTypeArrayOrUndefined,
|
||||
tags,
|
||||
} from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
@ -37,12 +37,12 @@ export const updateEndpointListItemSchema = t.intersection([
|
|||
),
|
||||
t.exact(
|
||||
t.partial({
|
||||
_tags, // defaults to empty array if not set during decode
|
||||
_version, // defaults to undefined if not set during decode
|
||||
comments: DefaultUpdateCommentsArray, // defaults to empty array if not set during decode
|
||||
id, // defaults to undefined if not set during decode
|
||||
item_id: t.union([t.string, t.undefined]),
|
||||
meta, // defaults to undefined if not set during decode
|
||||
os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode
|
||||
tags, // defaults to empty array if not set during decode
|
||||
})
|
||||
),
|
||||
|
@ -53,10 +53,10 @@ export type UpdateEndpointListItemSchema = t.OutputOf<typeof updateEndpointListI
|
|||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type UpdateEndpointListItemSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof updateEndpointListItemSchema>>,
|
||||
'_tags' | 'tags' | 'entries' | 'comments'
|
||||
'tags' | 'entries' | 'comments'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
comments: UpdateCommentsArray;
|
||||
tags: Tags;
|
||||
entries: EntriesArray;
|
||||
os_types: OsTypeArray;
|
||||
};
|
||||
|
|
|
@ -15,14 +15,13 @@ import {
|
|||
META,
|
||||
NAME,
|
||||
NAMESPACE_TYPE,
|
||||
OS_TYPES,
|
||||
TAGS,
|
||||
_TAGS,
|
||||
} from '../../constants.mock';
|
||||
|
||||
import { UpdateExceptionListItemSchema } from './update_exception_list_item_schema';
|
||||
|
||||
export const getUpdateExceptionListItemSchemaMock = (): UpdateExceptionListItemSchema => ({
|
||||
_tags: _TAGS,
|
||||
_version: undefined,
|
||||
comments: COMMENTS,
|
||||
description: DESCRIPTION,
|
||||
|
@ -32,6 +31,7 @@ export const getUpdateExceptionListItemSchemaMock = (): UpdateExceptionListItemS
|
|||
meta: META,
|
||||
name: NAME,
|
||||
namespace_type: NAMESPACE_TYPE,
|
||||
os_types: ['linux'],
|
||||
tags: TAGS,
|
||||
type: ITEM_TYPE,
|
||||
});
|
||||
|
@ -45,5 +45,6 @@ export const getUpdateMinimalExceptionListItemSchemaMock = (): UpdateExceptionLi
|
|||
entries: ENTRIES,
|
||||
item_id: ITEM_ID,
|
||||
name: NAME,
|
||||
os_types: OS_TYPES,
|
||||
type: ITEM_TYPE,
|
||||
});
|
||||
|
|
|
@ -139,18 +139,6 @@ describe('update_exception_list_item_schema', () => {
|
|||
expect(message.schema).toEqual(outputPayload);
|
||||
});
|
||||
|
||||
test('it should accept an undefined for "_tags" but return an array', () => {
|
||||
const inputPayload = getUpdateExceptionListItemSchemaMock();
|
||||
const outputPayload = getUpdateExceptionListItemSchemaMock();
|
||||
delete inputPayload._tags;
|
||||
outputPayload._tags = [];
|
||||
const decoded = updateExceptionListItemSchema.decode(inputPayload);
|
||||
const checked = exactCheck(inputPayload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
expect(message.schema).toEqual(outputPayload);
|
||||
});
|
||||
|
||||
test('it should accept an undefined for "item_id" and generate a correct body not counting the uuid', () => {
|
||||
const inputPayload = getUpdateExceptionListItemSchemaMock();
|
||||
delete inputPayload.item_id;
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import {
|
||||
OsTypeArray,
|
||||
Tags,
|
||||
_Tags,
|
||||
_tags,
|
||||
_version,
|
||||
description,
|
||||
exceptionListItemType,
|
||||
|
@ -17,6 +16,7 @@ import {
|
|||
meta,
|
||||
name,
|
||||
namespace_type,
|
||||
osTypeArrayOrUndefined,
|
||||
tags,
|
||||
} from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
@ -39,13 +39,13 @@ export const updateExceptionListItemSchema = t.intersection([
|
|||
),
|
||||
t.exact(
|
||||
t.partial({
|
||||
_tags, // defaults to empty array if not set during decode
|
||||
_version, // defaults to undefined if not set during decode
|
||||
comments: DefaultUpdateCommentsArray, // defaults to empty array if not set during decode
|
||||
id, // defaults to undefined if not set during decode
|
||||
item_id: t.union([t.string, t.undefined]),
|
||||
meta, // defaults to undefined if not set during decode
|
||||
namespace_type, // defaults to 'single' if not set during decode
|
||||
os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode
|
||||
tags, // defaults to empty array if not set during decode
|
||||
})
|
||||
),
|
||||
|
@ -56,11 +56,11 @@ export type UpdateExceptionListItemSchema = t.OutputOf<typeof updateExceptionLis
|
|||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type UpdateExceptionListItemSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof updateExceptionListItemSchema>>,
|
||||
'_tags' | 'tags' | 'entries' | 'namespace_type' | 'comments'
|
||||
'tags' | 'entries' | 'namespace_type' | 'comments' | 'os_types'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
comments: UpdateCommentsArray;
|
||||
tags: Tags;
|
||||
entries: EntriesArray;
|
||||
namespace_type: NamespaceType;
|
||||
os_types: OsTypeArray;
|
||||
};
|
||||
|
|
|
@ -4,12 +4,11 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { DESCRIPTION, ID, LIST_ID, META, NAME, NAMESPACE_TYPE, _TAGS } from '../../constants.mock';
|
||||
import { DESCRIPTION, ID, LIST_ID, META, NAME, NAMESPACE_TYPE } from '../../constants.mock';
|
||||
|
||||
import { UpdateExceptionListSchema } from './update_exception_list_schema';
|
||||
|
||||
export const getUpdateExceptionListSchemaMock = (): UpdateExceptionListSchema => ({
|
||||
_tags: _TAGS,
|
||||
_version: undefined,
|
||||
description: DESCRIPTION,
|
||||
id: ID,
|
||||
|
@ -17,6 +16,7 @@ export const getUpdateExceptionListSchemaMock = (): UpdateExceptionListSchema =>
|
|||
meta: META,
|
||||
name: NAME,
|
||||
namespace_type: NAMESPACE_TYPE,
|
||||
os_types: [],
|
||||
tags: ['malware'],
|
||||
type: 'endpoint',
|
||||
});
|
||||
|
|
|
@ -100,18 +100,6 @@ describe('update_exception_list_schema', () => {
|
|||
expect(message.schema).toEqual(outputPayload);
|
||||
});
|
||||
|
||||
test('it should accept an undefined for "_tags" but return an array', () => {
|
||||
const inputPayload = getUpdateExceptionListSchemaMock();
|
||||
const outputPayload = getUpdateExceptionListSchemaMock();
|
||||
delete inputPayload._tags;
|
||||
outputPayload._tags = [];
|
||||
const decoded = updateExceptionListSchema.decode(inputPayload);
|
||||
const checked = exactCheck(inputPayload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
expect(message.schema).toEqual(outputPayload);
|
||||
});
|
||||
|
||||
test('it should accept an undefined for "list_id" and generate a correct body not counting the uuid', () => {
|
||||
const inputPayload = getUpdateExceptionListSchemaMock();
|
||||
delete inputPayload.list_id;
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import {
|
||||
OsTypeArray,
|
||||
Tags,
|
||||
_Tags,
|
||||
_tags,
|
||||
_version,
|
||||
description,
|
||||
exceptionListType,
|
||||
|
@ -18,6 +17,7 @@ import {
|
|||
meta,
|
||||
name,
|
||||
namespace_type,
|
||||
osTypeArrayOrUndefined,
|
||||
tags,
|
||||
version,
|
||||
} from '../common/schemas';
|
||||
|
@ -34,12 +34,12 @@ export const updateExceptionListSchema = t.intersection([
|
|||
),
|
||||
t.exact(
|
||||
t.partial({
|
||||
_tags, // defaults to empty array if not set during decode
|
||||
_version, // defaults to undefined if not set during decode
|
||||
id, // defaults to undefined if not set during decode
|
||||
list_id, // defaults to undefined if not set during decode
|
||||
meta, // defaults to undefined if not set during decode
|
||||
namespace_type, // defaults to 'single' if not set during decode
|
||||
os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode
|
||||
tags, // defaults to empty array if not set during decode
|
||||
version, // defaults to undefined if not set during decode
|
||||
})
|
||||
|
@ -51,9 +51,9 @@ export type UpdateExceptionListSchema = t.OutputOf<typeof updateExceptionListSch
|
|||
// This type is used after a decode since the arrays turn into defaults of empty arrays.
|
||||
export type UpdateExceptionListSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof updateExceptionListSchema>>,
|
||||
'_tags | tags | namespace_type'
|
||||
'tags | namespace_type' | 'os_types'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
tags: Tags;
|
||||
namespace_type: NamespaceType;
|
||||
os_types: OsTypeArray;
|
||||
};
|
||||
|
|
|
@ -42,7 +42,7 @@ describe('create_endpoint_list_schema', () => {
|
|||
const message = pipe(checked, foldLeftRight);
|
||||
|
||||
expect(getPaths(left(message.errors))).toEqual([
|
||||
'invalid keys "_tags,["endpoint","process","malware","os:linux"],_version,created_at,created_by,description,id,immutable,meta,{},name,namespace_type,tags,["user added string for a tag","malware"],tie_breaker_id,type,updated_at,updated_by,version"',
|
||||
'invalid keys "_version,created_at,created_by,description,id,immutable,meta,{},name,namespace_type,os_types,["linux"],tags,["user added string for a tag","malware"],tie_breaker_id,type,updated_at,updated_by,version"',
|
||||
]);
|
||||
expect(message.schema).toEqual({});
|
||||
});
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
META,
|
||||
NAME,
|
||||
NAMESPACE_TYPE,
|
||||
OS_TYPES,
|
||||
TIE_BREAKER,
|
||||
USER,
|
||||
} from '../../constants.mock';
|
||||
|
@ -22,7 +23,6 @@ import {
|
|||
import { ExceptionListItemSchema } from './exception_list_item_schema';
|
||||
|
||||
export const getExceptionListItemSchemaMock = (): ExceptionListItemSchema => ({
|
||||
_tags: ['endpoint', 'process', 'malware', 'os:linux'],
|
||||
_version: undefined,
|
||||
comments: COMMENTS,
|
||||
created_at: DATE_NOW,
|
||||
|
@ -35,6 +35,7 @@ export const getExceptionListItemSchemaMock = (): ExceptionListItemSchema => ({
|
|||
meta: META,
|
||||
name: NAME,
|
||||
namespace_type: NAMESPACE_TYPE,
|
||||
os_types: ['linux'],
|
||||
tags: ['user added string for a tag', 'malware'],
|
||||
tie_breaker_id: TIE_BREAKER,
|
||||
type: ITEM_TYPE,
|
||||
|
@ -49,7 +50,6 @@ export const getExceptionListItemSchemaMock = (): ExceptionListItemSchema => ({
|
|||
export const getExceptionListItemResponseMockWithoutAutoGeneratedValues = (): Partial<
|
||||
ExceptionListItemSchema
|
||||
> => ({
|
||||
_tags: [],
|
||||
comments: [],
|
||||
created_by: ELASTIC_USER,
|
||||
description: DESCRIPTION,
|
||||
|
@ -58,6 +58,7 @@ export const getExceptionListItemResponseMockWithoutAutoGeneratedValues = (): Pa
|
|||
list_id: LIST_ID,
|
||||
name: NAME,
|
||||
namespace_type: 'single',
|
||||
os_types: OS_TYPES,
|
||||
tags: [],
|
||||
type: ITEM_TYPE,
|
||||
updated_by: ELASTIC_USER,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import {
|
||||
_tags,
|
||||
_versionOrUndefined,
|
||||
created_at,
|
||||
created_by,
|
||||
|
@ -19,6 +18,7 @@ import {
|
|||
metaOrUndefined,
|
||||
name,
|
||||
namespace_type,
|
||||
osTypeArray,
|
||||
tags,
|
||||
tie_breaker_id,
|
||||
updated_at,
|
||||
|
@ -28,7 +28,6 @@ import { commentsArray, entriesArray } from '../types';
|
|||
|
||||
export const exceptionListItemSchema = t.exact(
|
||||
t.type({
|
||||
_tags,
|
||||
_version: _versionOrUndefined,
|
||||
comments: commentsArray,
|
||||
created_at,
|
||||
|
@ -41,6 +40,7 @@ export const exceptionListItemSchema = t.exact(
|
|||
meta: metaOrUndefined,
|
||||
name,
|
||||
namespace_type,
|
||||
os_types: osTypeArray,
|
||||
tags,
|
||||
tie_breaker_id,
|
||||
type: exceptionListItemType,
|
||||
|
|
|
@ -28,7 +28,6 @@ import {
|
|||
import { ExceptionListSchema } from './exception_list_schema';
|
||||
|
||||
export const getExceptionListSchemaMock = (): ExceptionListSchema => ({
|
||||
_tags: ['endpoint', 'process', 'malware', 'os:linux'],
|
||||
_version: _VERSION,
|
||||
created_at: DATE_NOW,
|
||||
created_by: USER,
|
||||
|
@ -39,6 +38,7 @@ export const getExceptionListSchemaMock = (): ExceptionListSchema => ({
|
|||
meta: META,
|
||||
name: 'Sample Endpoint Exception List',
|
||||
namespace_type: 'agnostic',
|
||||
os_types: ['linux'],
|
||||
tags: ['user added string for a tag', 'malware'],
|
||||
tie_breaker_id: TIE_BREAKER,
|
||||
type: ENDPOINT_TYPE,
|
||||
|
@ -63,13 +63,13 @@ export const getTrustedAppsListSchemaMock = (): ExceptionListSchema => {
|
|||
export const getExceptionResponseMockWithoutAutoGeneratedValues = (): Partial<
|
||||
ExceptionListSchema
|
||||
> => ({
|
||||
_tags: [],
|
||||
created_by: ELASTIC_USER,
|
||||
description: DESCRIPTION,
|
||||
immutable: IMMUTABLE,
|
||||
list_id: LIST_ID,
|
||||
name: NAME,
|
||||
namespace_type: 'single',
|
||||
os_types: [],
|
||||
tags: [],
|
||||
type: ENDPOINT_TYPE,
|
||||
updated_by: ELASTIC_USER,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import {
|
||||
_tags,
|
||||
_versionOrUndefined,
|
||||
created_at,
|
||||
created_by,
|
||||
|
@ -19,6 +18,7 @@ import {
|
|||
metaOrUndefined,
|
||||
name,
|
||||
namespace_type,
|
||||
osTypeArray,
|
||||
tags,
|
||||
tie_breaker_id,
|
||||
updated_at,
|
||||
|
@ -28,7 +28,6 @@ import {
|
|||
|
||||
export const exceptionListSchema = t.exact(
|
||||
t.type({
|
||||
_tags,
|
||||
_version: _versionOrUndefined,
|
||||
created_at,
|
||||
created_by,
|
||||
|
@ -39,6 +38,7 @@ export const exceptionListSchema = t.exact(
|
|||
meta: metaOrUndefined,
|
||||
name,
|
||||
namespace_type,
|
||||
os_types: osTypeArray,
|
||||
tags,
|
||||
tie_breaker_id,
|
||||
type: exceptionListType,
|
||||
|
|
|
@ -8,7 +8,6 @@ import * as t from 'io-ts';
|
|||
|
||||
import { commentsArrayOrUndefined, entriesArrayOrUndefined } from '../types';
|
||||
import {
|
||||
_tags,
|
||||
created_at,
|
||||
created_by,
|
||||
description,
|
||||
|
@ -20,6 +19,7 @@ import {
|
|||
list_type,
|
||||
metaOrUndefined,
|
||||
name,
|
||||
osTypeArray,
|
||||
tags,
|
||||
tie_breaker_id,
|
||||
updated_by,
|
||||
|
@ -31,7 +31,6 @@ import {
|
|||
*/
|
||||
export const exceptionListSoSchema = t.exact(
|
||||
t.type({
|
||||
_tags,
|
||||
comments: commentsArrayOrUndefined,
|
||||
created_at,
|
||||
created_by,
|
||||
|
@ -43,6 +42,7 @@ export const exceptionListSoSchema = t.exact(
|
|||
list_type,
|
||||
meta: metaOrUndefined,
|
||||
name,
|
||||
os_types: osTypeArray,
|
||||
tags,
|
||||
tie_breaker_id,
|
||||
type: t.union([exceptionListType, exceptionListItemType]),
|
||||
|
|
|
@ -41,6 +41,8 @@ export {
|
|||
namespaceType,
|
||||
ExceptionListType,
|
||||
Type,
|
||||
osTypeArray,
|
||||
OsTypeArray,
|
||||
} from './schemas';
|
||||
|
||||
export { ENDPOINT_LIST_ID } from './constants';
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
export {
|
||||
NonEmptyString,
|
||||
DefaultArray,
|
||||
DefaultUuid,
|
||||
DefaultStringArray,
|
||||
DefaultVersionNumber,
|
||||
|
|
|
@ -37,13 +37,13 @@ export const createEndpointListItemRoute = (router: IRouter): void => {
|
|||
try {
|
||||
const {
|
||||
name,
|
||||
_tags,
|
||||
tags,
|
||||
meta,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
item_id: itemId,
|
||||
os_types: osTypes,
|
||||
type,
|
||||
} = request.body;
|
||||
const exceptionLists = getExceptionListClient(context);
|
||||
|
@ -58,13 +58,13 @@ export const createEndpointListItemRoute = (router: IRouter): void => {
|
|||
});
|
||||
} else {
|
||||
const createdList = await exceptionLists.createEndpointListItem({
|
||||
_tags,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
itemId,
|
||||
meta,
|
||||
name,
|
||||
osTypes,
|
||||
tags,
|
||||
type,
|
||||
});
|
||||
|
|
|
@ -39,7 +39,6 @@ export const createExceptionListItemRoute = (router: IRouter): void => {
|
|||
const {
|
||||
namespace_type: namespaceType,
|
||||
name,
|
||||
_tags,
|
||||
tags,
|
||||
meta,
|
||||
comments,
|
||||
|
@ -47,6 +46,7 @@ export const createExceptionListItemRoute = (router: IRouter): void => {
|
|||
entries,
|
||||
item_id: itemId,
|
||||
list_id: listId,
|
||||
os_types: osTypes,
|
||||
type,
|
||||
} = request.body;
|
||||
const exceptionLists = getExceptionListClient(context);
|
||||
|
@ -87,7 +87,6 @@ export const createExceptionListItemRoute = (router: IRouter): void => {
|
|||
}
|
||||
}
|
||||
const createdList = await exceptionLists.createExceptionListItem({
|
||||
_tags,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
|
@ -96,6 +95,7 @@ export const createExceptionListItemRoute = (router: IRouter): void => {
|
|||
meta,
|
||||
name,
|
||||
namespaceType,
|
||||
osTypes,
|
||||
tags,
|
||||
type,
|
||||
});
|
||||
|
|
|
@ -36,7 +36,6 @@ export const createExceptionListRoute = (router: IRouter): void => {
|
|||
try {
|
||||
const {
|
||||
name,
|
||||
_tags,
|
||||
tags,
|
||||
meta,
|
||||
namespace_type: namespaceType,
|
||||
|
@ -58,7 +57,6 @@ export const createExceptionListRoute = (router: IRouter): void => {
|
|||
});
|
||||
} else {
|
||||
const createdList = await exceptionLists.createExceptionList({
|
||||
_tags,
|
||||
description,
|
||||
immutable: false,
|
||||
listId,
|
||||
|
|
|
@ -38,9 +38,9 @@ export const updateEndpointListItemRoute = (router: IRouter): void => {
|
|||
description,
|
||||
id,
|
||||
name,
|
||||
os_types: osTypes,
|
||||
meta,
|
||||
type,
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
entries,
|
||||
|
@ -49,7 +49,6 @@ export const updateEndpointListItemRoute = (router: IRouter): void => {
|
|||
} = request.body;
|
||||
const exceptionLists = getExceptionListClient(context);
|
||||
const exceptionListItem = await exceptionLists.updateEndpointListItem({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
|
@ -58,6 +57,7 @@ export const updateEndpointListItemRoute = (router: IRouter): void => {
|
|||
itemId,
|
||||
meta,
|
||||
name,
|
||||
osTypes,
|
||||
tags,
|
||||
type,
|
||||
});
|
||||
|
|
|
@ -46,12 +46,12 @@ export const updateExceptionListItemRoute = (router: IRouter): void => {
|
|||
name,
|
||||
meta,
|
||||
type,
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
entries,
|
||||
item_id: itemId,
|
||||
namespace_type: namespaceType,
|
||||
os_types: osTypes,
|
||||
tags,
|
||||
} = request.body;
|
||||
if (id == null && itemId == null) {
|
||||
|
@ -62,7 +62,6 @@ export const updateExceptionListItemRoute = (router: IRouter): void => {
|
|||
} else {
|
||||
const exceptionLists = getExceptionListClient(context);
|
||||
const exceptionListItem = await exceptionLists.updateExceptionListItem({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
|
@ -72,6 +71,7 @@ export const updateExceptionListItemRoute = (router: IRouter): void => {
|
|||
meta,
|
||||
name,
|
||||
namespaceType,
|
||||
osTypes,
|
||||
tags,
|
||||
type,
|
||||
});
|
||||
|
|
|
@ -35,7 +35,6 @@ export const updateExceptionListRoute = (router: IRouter): void => {
|
|||
const siemResponse = buildSiemResponse(response);
|
||||
try {
|
||||
const {
|
||||
_tags,
|
||||
_version,
|
||||
tags,
|
||||
name,
|
||||
|
@ -44,6 +43,7 @@ export const updateExceptionListRoute = (router: IRouter): void => {
|
|||
list_id: listId,
|
||||
meta,
|
||||
namespace_type: namespaceType,
|
||||
os_types: osTypes,
|
||||
type,
|
||||
version,
|
||||
} = request.body;
|
||||
|
@ -55,7 +55,6 @@ export const updateExceptionListRoute = (router: IRouter): void => {
|
|||
});
|
||||
} else {
|
||||
const list = await exceptionLists.updateExceptionList({
|
||||
_tags,
|
||||
_version,
|
||||
description,
|
||||
id,
|
||||
|
@ -63,6 +62,7 @@ export const updateExceptionListRoute = (router: IRouter): void => {
|
|||
meta,
|
||||
name,
|
||||
namespaceType,
|
||||
osTypes,
|
||||
tags,
|
||||
type,
|
||||
version,
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
import { SavedObjectsType } from 'kibana/server';
|
||||
|
||||
import { migrations } from './migrations';
|
||||
|
||||
export const exceptionListSavedObjectType = 'exception-list';
|
||||
export const exceptionListAgnosticSavedObjectType = 'exception-list-agnostic';
|
||||
export type SavedObjectType = 'exception-list' | 'exception-list-agnostic';
|
||||
|
@ -149,6 +151,9 @@ export const exceptionListItemMapping: SavedObjectsType['mappings'] = {
|
|||
item_id: {
|
||||
type: 'keyword',
|
||||
},
|
||||
os_types: {
|
||||
type: 'keyword',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -163,6 +168,7 @@ const combinedMappings: SavedObjectsType['mappings'] = {
|
|||
export const exceptionListType: SavedObjectsType = {
|
||||
hidden: false,
|
||||
mappings: combinedMappings,
|
||||
migrations,
|
||||
name: exceptionListSavedObjectType,
|
||||
namespaceType: 'single',
|
||||
};
|
||||
|
@ -170,6 +176,7 @@ export const exceptionListType: SavedObjectsType = {
|
|||
export const exceptionListAgnosticType: SavedObjectsType = {
|
||||
hidden: false,
|
||||
mappings: combinedMappings,
|
||||
migrations,
|
||||
name: exceptionListAgnosticSavedObjectType,
|
||||
namespaceType: 'agnostic',
|
||||
};
|
||||
|
|
132
x-pack/plugins/lists/server/saved_objects/migrations.test.ts
Normal file
132
x-pack/plugins/lists/server/saved_objects/migrations.test.ts
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { SavedObjectUnsanitizedDoc } from 'kibana/server';
|
||||
|
||||
import { ENDPOINT_LIST_ID } from '../../common/constants';
|
||||
|
||||
import { OldExceptionListSoSchema, migrations } from './migrations';
|
||||
|
||||
describe('7.10.0 lists migrations', () => {
|
||||
const migration = migrations['7.10.0'];
|
||||
|
||||
test('properly converts .text fields to .caseless', () => {
|
||||
const doc = {
|
||||
attributes: {
|
||||
entries: [
|
||||
{
|
||||
field: 'file.path.text',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: 'C:\\Windows\\explorer.exe',
|
||||
},
|
||||
{
|
||||
field: 'host.os.name',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: 'my-host',
|
||||
},
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
field: 'process.command_line.text',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: '/usr/bin/bash',
|
||||
},
|
||||
{
|
||||
field: 'process.parent.command_line.text',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: '/usr/bin/bash',
|
||||
},
|
||||
],
|
||||
field: 'nested.field',
|
||||
type: 'nested',
|
||||
},
|
||||
],
|
||||
list_id: ENDPOINT_LIST_ID,
|
||||
},
|
||||
id: 'abcd',
|
||||
migrationVersion: {},
|
||||
references: [],
|
||||
type: 'so-type',
|
||||
updated_at: '2020-06-09T20:18:20.349Z',
|
||||
};
|
||||
expect(
|
||||
migration((doc as unknown) as SavedObjectUnsanitizedDoc<OldExceptionListSoSchema>)
|
||||
).toEqual({
|
||||
attributes: {
|
||||
entries: [
|
||||
{
|
||||
field: 'file.path.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: 'C:\\Windows\\explorer.exe',
|
||||
},
|
||||
{
|
||||
field: 'host.os.name',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: 'my-host',
|
||||
},
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
field: 'process.command_line.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: '/usr/bin/bash',
|
||||
},
|
||||
{
|
||||
field: 'process.parent.command_line.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: '/usr/bin/bash',
|
||||
},
|
||||
],
|
||||
field: 'nested.field',
|
||||
type: 'nested',
|
||||
},
|
||||
],
|
||||
list_id: ENDPOINT_LIST_ID,
|
||||
},
|
||||
id: 'abcd',
|
||||
migrationVersion: {},
|
||||
references: [],
|
||||
type: 'so-type',
|
||||
updated_at: '2020-06-09T20:18:20.349Z',
|
||||
});
|
||||
});
|
||||
|
||||
test('properly copies os tags to os_types', () => {
|
||||
const doc = {
|
||||
attributes: {
|
||||
_tags: ['1234', 'os:windows'],
|
||||
comments: [],
|
||||
},
|
||||
id: 'abcd',
|
||||
migrationVersion: {},
|
||||
references: [],
|
||||
type: 'so-type',
|
||||
updated_at: '2020-06-09T20:18:20.349Z',
|
||||
};
|
||||
expect(
|
||||
migration((doc as unknown) as SavedObjectUnsanitizedDoc<OldExceptionListSoSchema>)
|
||||
).toEqual({
|
||||
attributes: {
|
||||
_tags: ['1234', 'os:windows'],
|
||||
comments: [],
|
||||
os_types: ['windows'],
|
||||
},
|
||||
id: 'abcd',
|
||||
migrationVersion: {},
|
||||
references: [],
|
||||
type: 'so-type',
|
||||
updated_at: '2020-06-09T20:18:20.349Z',
|
||||
});
|
||||
});
|
||||
});
|
66
x-pack/plugins/lists/server/saved_objects/migrations.ts
Normal file
66
x-pack/plugins/lists/server/saved_objects/migrations.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { SavedObjectSanitizedDoc, SavedObjectUnsanitizedDoc } from 'kibana/server';
|
||||
|
||||
import { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../common/constants';
|
||||
import {
|
||||
EntriesArray,
|
||||
ExceptionListSoSchema,
|
||||
NonEmptyNestedEntriesArray,
|
||||
OsTypeArray,
|
||||
entriesNested,
|
||||
entry,
|
||||
} from '../../common/schemas';
|
||||
|
||||
const entryType = t.union([entry, entriesNested]);
|
||||
type EntryType = t.TypeOf<typeof entryType>;
|
||||
|
||||
const migrateEntry = (entryToMigrate: EntryType): EntryType => {
|
||||
const newEntry = entryToMigrate;
|
||||
if (entriesNested.is(entryToMigrate) && entriesNested.is(newEntry)) {
|
||||
newEntry.entries = entryToMigrate.entries.map((nestedEntry) =>
|
||||
migrateEntry(nestedEntry)
|
||||
) as NonEmptyNestedEntriesArray;
|
||||
}
|
||||
newEntry.field = entryToMigrate.field.replace('.text', '.caseless');
|
||||
return newEntry;
|
||||
};
|
||||
|
||||
const reduceOsTypes = (acc: string[], tag: string): string[] => {
|
||||
if (tag.startsWith('os:')) {
|
||||
// TODO: check OS against type
|
||||
return [...acc, tag.replace('os:', '')];
|
||||
}
|
||||
return [...acc];
|
||||
};
|
||||
|
||||
export type OldExceptionListSoSchema = ExceptionListSoSchema & {
|
||||
_tags: string[];
|
||||
};
|
||||
|
||||
export const migrations = {
|
||||
'7.10.0': (
|
||||
doc: SavedObjectUnsanitizedDoc<OldExceptionListSoSchema>
|
||||
): SavedObjectSanitizedDoc<ExceptionListSoSchema> => ({
|
||||
...doc,
|
||||
...{
|
||||
attributes: {
|
||||
...doc.attributes,
|
||||
...(doc.attributes.entries &&
|
||||
[ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID].includes(doc.attributes.list_id) && {
|
||||
entries: (doc.attributes.entries as EntriesArray).map<EntryType>(migrateEntry),
|
||||
}),
|
||||
...(doc.attributes._tags &&
|
||||
doc.attributes._tags.reduce(reduceOsTypes, []).length > 0 && {
|
||||
os_types: doc.attributes._tags.reduce(reduceOsTypes, []) as OsTypeArray,
|
||||
}),
|
||||
},
|
||||
},
|
||||
references: doc.references || [],
|
||||
}),
|
||||
};
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"item_id": "simple_list_item",
|
||||
"_tags": ["endpoint", "process", "malware", "os:linux"],
|
||||
"tags": ["user added string for a tag", "malware"],
|
||||
"type": "simple",
|
||||
"description": "This is a sample endpoint type exception",
|
||||
"name": "Sample Endpoint Exception List",
|
||||
"os_types": ["linux"],
|
||||
"entries": [
|
||||
{
|
||||
"field": "actingProcess.file.signer",
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{
|
||||
"list_id": "simple_list",
|
||||
"_tags": ["endpoint", "process", "malware", "os:linux"],
|
||||
"tags": ["user added string for a tag", "malware"],
|
||||
"type": "detection",
|
||||
"description": "This is a sample endpoint type exception",
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{
|
||||
"list_id": "endpoint_list",
|
||||
"_tags": ["endpoint", "process", "malware", "os:linux"],
|
||||
"tags": ["user added string for a tag", "malware"],
|
||||
"type": "endpoint",
|
||||
"description": "This is a sample agnostic endpoint type exception",
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{
|
||||
"list_id": "detection_list",
|
||||
"_tags": ["detection"],
|
||||
"tags": ["detection", "sample_tag"],
|
||||
"type": "detection",
|
||||
"description": "This is a sample detection type exception list",
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"list_id": "simple_list",
|
||||
"item_id": "simple_list_item",
|
||||
"_tags": ["endpoint", "process", "malware", "os:linux"],
|
||||
"tags": ["user added string for a tag", "malware"],
|
||||
"type": "simple",
|
||||
"description": "This is a sample endpoint type exception",
|
||||
"name": "Sample Endpoint Exception List",
|
||||
"os_types": ["linux"],
|
||||
"entries": [
|
||||
{
|
||||
"field": "actingProcess.file.signer",
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"list_id": "endpoint_list",
|
||||
"item_id": "endpoint_list_item",
|
||||
"_tags": ["endpoint", "process", "malware", "os:linux"],
|
||||
"tags": ["user added string for a tag", "malware"],
|
||||
"type": "simple",
|
||||
"description": "This is a sample agnostic endpoint type exception",
|
||||
"name": "Sample Endpoint Exception List",
|
||||
"namespace_type": "agnostic",
|
||||
"os_types": ["linux"],
|
||||
"entries": [
|
||||
{
|
||||
"field": "actingProcess.file.signer",
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"list_id": "simple_list",
|
||||
"_tags": ["endpoint", "process", "malware", "os:linux"],
|
||||
"tags": ["user added string for a tag", "malware"],
|
||||
"type": "simple",
|
||||
"description": "This is a sample endpoint type exception that has no item_id so it creates a new id each time",
|
||||
"name": "Sample Endpoint Exception List",
|
||||
"os_types": ["linux"],
|
||||
"comments": [],
|
||||
"entries": [
|
||||
{
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{
|
||||
"list_id": "detection_list",
|
||||
"_tags": ["detection"],
|
||||
"tags": ["test_tag", "detection", "no_more_bad_guys"],
|
||||
"type": "simple",
|
||||
"description": "This is a sample detection type exception that has no item_id so it creates a new id each time",
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"list_id": "endpoint_list",
|
||||
"item_id": "endpoint_list_item_good_rock01",
|
||||
"_tags": ["endpoint", "process", "malware", "os:windows"],
|
||||
"tags": ["user added string for a tag", "malware"],
|
||||
"type": "simple",
|
||||
"description": "Don't signal when agent.name is rock01 and source.ip is in the goodguys.txt list",
|
||||
"name": "Filter out good guys ip and agent.name rock01",
|
||||
"os_types": ["windows"],
|
||||
"comments": [],
|
||||
"entries": [
|
||||
{
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"list_id": "endpoint_list",
|
||||
"item_id": "endpoint_list_item_lg_val_list",
|
||||
"_tags": ["endpoint", "process", "malware", "os:windows"],
|
||||
"tags": ["user added string for a tag", "malware"],
|
||||
"type": "simple",
|
||||
"description": "This is a sample exception list item with a large value list included",
|
||||
"name": "Sample Endpoint Exception List Item with large value list",
|
||||
"os_types": ["windows"],
|
||||
"comments": [],
|
||||
"entries": [
|
||||
{
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"list_id": "endpoint_trusted_apps",
|
||||
"item_id": "endpoint_trusted_apps_item",
|
||||
"_tags": ["endpoint", "os:linux", "os:windows", "os:macos", "trusted-app"],
|
||||
"tags": ["user added string for a tag", "malware"],
|
||||
"type": "simple",
|
||||
"description": "This is a sample agnostic endpoint trusted app entry",
|
||||
"name": "Sample Endpoint Trusted App Entry",
|
||||
"namespace_type": "agnostic",
|
||||
"os_types": ["linux", "windows", "macos"],
|
||||
"entries": [
|
||||
{
|
||||
"field": "actingProcess.file.signer",
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"list_id": "simple_list",
|
||||
"_tags": ["endpoint", "process", "malware", "os:linux"],
|
||||
"tags": ["user added string for a tag", "malware"],
|
||||
"type": "endpoint",
|
||||
"os_types": ["linux"],
|
||||
"description": "Different description",
|
||||
"name": "Sample Endpoint Exception List"
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"item_id": "endpoint_list_item",
|
||||
"_tags": ["endpoint", "process", "malware", "os:windows"],
|
||||
"tags": ["user added string for a tag", "malware"],
|
||||
"type": "simple",
|
||||
"description": "This is a sample agnostic change here this list",
|
||||
"name": "Sample Endpoint Exception List update change",
|
||||
"namespace_type": "agnostic",
|
||||
"os_types": ["windows"],
|
||||
"entries": [
|
||||
{
|
||||
"field": "event.category",
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"_tags": ["detection"],
|
||||
"comments": [],
|
||||
"description": "Test comments - exception list item",
|
||||
"entries": [
|
||||
|
|
|
@ -35,7 +35,6 @@ export const createEndpointList = async ({
|
|||
const savedObject = await savedObjectsClient.create<ExceptionListSoSchema>(
|
||||
savedObjectType,
|
||||
{
|
||||
_tags: [],
|
||||
comments: undefined,
|
||||
created_at: dateNow,
|
||||
created_by: user,
|
||||
|
@ -47,6 +46,7 @@ export const createEndpointList = async ({
|
|||
list_type: 'list',
|
||||
meta: undefined,
|
||||
name: ENDPOINT_LIST_NAME,
|
||||
os_types: [],
|
||||
tags: [],
|
||||
tie_breaker_id: tieBreaker ?? uuid.v4(),
|
||||
type: 'endpoint',
|
||||
|
|
|
@ -43,7 +43,6 @@ export const createEndpointTrustedAppsList = async ({
|
|||
const savedObject = await savedObjectsClient.create<ExceptionListSoSchema>(
|
||||
savedObjectType,
|
||||
{
|
||||
_tags: [],
|
||||
comments: undefined,
|
||||
created_at: dateNow,
|
||||
created_by: user,
|
||||
|
@ -55,6 +54,7 @@ export const createEndpointTrustedAppsList = async ({
|
|||
list_type: 'list',
|
||||
meta: undefined,
|
||||
name: ENDPOINT_TRUSTED_APPS_LIST_NAME,
|
||||
os_types: [],
|
||||
tags: [],
|
||||
tie_breaker_id: tieBreaker ?? uuid.v4(),
|
||||
type: 'endpoint',
|
||||
|
|
|
@ -19,13 +19,11 @@ import {
|
|||
NamespaceType,
|
||||
Tags,
|
||||
Version,
|
||||
_Tags,
|
||||
} from '../../../common/schemas';
|
||||
|
||||
import { getSavedObjectType, transformSavedObjectToExceptionList } from './utils';
|
||||
|
||||
interface CreateExceptionListOptions {
|
||||
_tags: _Tags;
|
||||
listId: ListId;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
namespaceType: NamespaceType;
|
||||
|
@ -41,7 +39,6 @@ interface CreateExceptionListOptions {
|
|||
}
|
||||
|
||||
export const createExceptionList = async ({
|
||||
_tags,
|
||||
listId,
|
||||
immutable,
|
||||
savedObjectsClient,
|
||||
|
@ -58,7 +55,6 @@ export const createExceptionList = async ({
|
|||
const savedObjectType = getSavedObjectType({ namespaceType });
|
||||
const dateNow = new Date().toISOString();
|
||||
const savedObject = await savedObjectsClient.create<ExceptionListSoSchema>(savedObjectType, {
|
||||
_tags,
|
||||
comments: undefined,
|
||||
created_at: dateNow,
|
||||
created_by: user,
|
||||
|
@ -70,6 +66,7 @@ export const createExceptionList = async ({
|
|||
list_type: 'list',
|
||||
meta,
|
||||
name,
|
||||
os_types: [],
|
||||
tags,
|
||||
tie_breaker_id: tieBreaker ?? uuid.v4(),
|
||||
type,
|
||||
|
|
|
@ -19,8 +19,8 @@ import {
|
|||
MetaOrUndefined,
|
||||
Name,
|
||||
NamespaceType,
|
||||
OsTypeArray,
|
||||
Tags,
|
||||
_Tags,
|
||||
} from '../../../common/schemas';
|
||||
|
||||
import {
|
||||
|
@ -30,7 +30,6 @@ import {
|
|||
} from './utils';
|
||||
|
||||
interface CreateExceptionListItemOptions {
|
||||
_tags: _Tags;
|
||||
comments: CreateCommentsArray;
|
||||
listId: ListId;
|
||||
itemId: ItemId;
|
||||
|
@ -44,10 +43,10 @@ interface CreateExceptionListItemOptions {
|
|||
tags: Tags;
|
||||
tieBreaker?: string;
|
||||
type: ExceptionListItemType;
|
||||
osTypes: OsTypeArray;
|
||||
}
|
||||
|
||||
export const createExceptionListItem = async ({
|
||||
_tags,
|
||||
comments,
|
||||
entries,
|
||||
itemId,
|
||||
|
@ -55,6 +54,7 @@ export const createExceptionListItem = async ({
|
|||
savedObjectsClient,
|
||||
namespaceType,
|
||||
name,
|
||||
osTypes,
|
||||
description,
|
||||
meta,
|
||||
user,
|
||||
|
@ -69,7 +69,6 @@ export const createExceptionListItem = async ({
|
|||
user,
|
||||
});
|
||||
const savedObject = await savedObjectsClient.create<ExceptionListSoSchema>(savedObjectType, {
|
||||
_tags,
|
||||
comments: transformedComments,
|
||||
created_at: dateNow,
|
||||
created_by: user,
|
||||
|
@ -81,6 +80,7 @@ export const createExceptionListItem = async ({
|
|||
list_type: 'item',
|
||||
meta,
|
||||
name,
|
||||
os_types: osTypes as OsTypeArray,
|
||||
tags,
|
||||
tie_breaker_id: tieBreaker ?? uuid.v4(),
|
||||
type,
|
||||
|
|
|
@ -109,20 +109,19 @@ export class ExceptionListClient {
|
|||
* being there and existing before the item is inserted into the agnostic endpoint list.
|
||||
*/
|
||||
public createEndpointListItem = async ({
|
||||
_tags,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
itemId,
|
||||
meta,
|
||||
name,
|
||||
osTypes,
|
||||
tags,
|
||||
type,
|
||||
}: CreateEndpointListItemOptions): Promise<ExceptionListItemSchema> => {
|
||||
const { savedObjectsClient, user } = this;
|
||||
await this.createEndpointList();
|
||||
return createExceptionListItem({
|
||||
_tags,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
|
@ -131,6 +130,7 @@ export class ExceptionListClient {
|
|||
meta,
|
||||
name,
|
||||
namespaceType: 'agnostic',
|
||||
osTypes,
|
||||
savedObjectsClient,
|
||||
tags,
|
||||
type,
|
||||
|
@ -145,7 +145,6 @@ export class ExceptionListClient {
|
|||
* return of null but at least the list exists again.
|
||||
*/
|
||||
public updateEndpointListItem = async ({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
|
@ -154,13 +153,13 @@ export class ExceptionListClient {
|
|||
itemId,
|
||||
meta,
|
||||
name,
|
||||
osTypes,
|
||||
tags,
|
||||
type,
|
||||
}: UpdateEndpointListItemOptions): Promise<ExceptionListItemSchema | null> => {
|
||||
const { savedObjectsClient, user } = this;
|
||||
await this.createEndpointList();
|
||||
return updateExceptionListItem({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
|
@ -170,6 +169,7 @@ export class ExceptionListClient {
|
|||
meta,
|
||||
name,
|
||||
namespaceType: 'agnostic',
|
||||
osTypes,
|
||||
savedObjectsClient,
|
||||
tags,
|
||||
type,
|
||||
|
@ -189,7 +189,6 @@ export class ExceptionListClient {
|
|||
};
|
||||
|
||||
public createExceptionList = async ({
|
||||
_tags,
|
||||
description,
|
||||
immutable,
|
||||
listId,
|
||||
|
@ -202,7 +201,6 @@ export class ExceptionListClient {
|
|||
}: CreateExceptionListOptions): Promise<ExceptionListSchema> => {
|
||||
const { savedObjectsClient, user } = this;
|
||||
return createExceptionList({
|
||||
_tags,
|
||||
description,
|
||||
immutable,
|
||||
listId,
|
||||
|
@ -218,7 +216,6 @@ export class ExceptionListClient {
|
|||
};
|
||||
|
||||
public updateExceptionList = async ({
|
||||
_tags,
|
||||
_version,
|
||||
id,
|
||||
description,
|
||||
|
@ -226,13 +223,13 @@ export class ExceptionListClient {
|
|||
meta,
|
||||
name,
|
||||
namespaceType,
|
||||
osTypes,
|
||||
tags,
|
||||
type,
|
||||
version,
|
||||
}: UpdateExceptionListOptions): Promise<ExceptionListSchema | null> => {
|
||||
const { savedObjectsClient, user } = this;
|
||||
return updateExceptionList({
|
||||
_tags,
|
||||
_version,
|
||||
description,
|
||||
id,
|
||||
|
@ -240,6 +237,7 @@ export class ExceptionListClient {
|
|||
meta,
|
||||
name,
|
||||
namespaceType,
|
||||
osTypes,
|
||||
savedObjectsClient,
|
||||
tags,
|
||||
type,
|
||||
|
@ -263,7 +261,6 @@ export class ExceptionListClient {
|
|||
};
|
||||
|
||||
public createExceptionListItem = async ({
|
||||
_tags,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
|
@ -272,12 +269,12 @@ export class ExceptionListClient {
|
|||
meta,
|
||||
name,
|
||||
namespaceType,
|
||||
osTypes,
|
||||
tags,
|
||||
type,
|
||||
}: CreateExceptionListItemOptions): Promise<ExceptionListItemSchema> => {
|
||||
const { savedObjectsClient, user } = this;
|
||||
return createExceptionListItem({
|
||||
_tags,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
|
@ -286,6 +283,7 @@ export class ExceptionListClient {
|
|||
meta,
|
||||
name,
|
||||
namespaceType,
|
||||
osTypes,
|
||||
savedObjectsClient,
|
||||
tags,
|
||||
type,
|
||||
|
@ -294,7 +292,6 @@ export class ExceptionListClient {
|
|||
};
|
||||
|
||||
public updateExceptionListItem = async ({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
|
@ -304,12 +301,12 @@ export class ExceptionListClient {
|
|||
meta,
|
||||
name,
|
||||
namespaceType,
|
||||
osTypes,
|
||||
tags,
|
||||
type,
|
||||
}: UpdateExceptionListItemOptions): Promise<ExceptionListItemSchema | null> => {
|
||||
const { savedObjectsClient, user } = this;
|
||||
return updateExceptionListItem({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
|
@ -319,6 +316,7 @@ export class ExceptionListClient {
|
|||
meta,
|
||||
name,
|
||||
namespaceType,
|
||||
osTypes,
|
||||
savedObjectsClient,
|
||||
tags,
|
||||
type,
|
||||
|
|
|
@ -30,6 +30,7 @@ import {
|
|||
Name,
|
||||
NameOrUndefined,
|
||||
NamespaceType,
|
||||
OsTypeArray,
|
||||
PageOrUndefined,
|
||||
PerPageOrUndefined,
|
||||
SortFieldOrUndefined,
|
||||
|
@ -39,8 +40,6 @@ import {
|
|||
UpdateCommentsArray,
|
||||
Version,
|
||||
VersionOrUndefined,
|
||||
_Tags,
|
||||
_TagsOrUndefined,
|
||||
_VersionOrUndefined,
|
||||
} from '../../../common/schemas';
|
||||
|
||||
|
@ -56,7 +55,6 @@ export interface GetExceptionListOptions {
|
|||
}
|
||||
|
||||
export interface CreateExceptionListOptions {
|
||||
_tags: _Tags;
|
||||
listId: ListId;
|
||||
namespaceType: NamespaceType;
|
||||
name: Name;
|
||||
|
@ -69,12 +67,12 @@ export interface CreateExceptionListOptions {
|
|||
}
|
||||
|
||||
export interface UpdateExceptionListOptions {
|
||||
_tags: _TagsOrUndefined;
|
||||
_version: _VersionOrUndefined;
|
||||
id: IdOrUndefined;
|
||||
listId: ListIdOrUndefined;
|
||||
namespaceType: NamespaceType;
|
||||
name: NameOrUndefined;
|
||||
osTypes: OsTypeArray;
|
||||
description: DescriptionOrUndefined;
|
||||
meta: MetaOrUndefined;
|
||||
tags: TagsOrUndefined;
|
||||
|
@ -116,13 +114,13 @@ export interface GetEndpointListItemOptions {
|
|||
}
|
||||
|
||||
export interface CreateExceptionListItemOptions {
|
||||
_tags: _Tags;
|
||||
comments: CreateCommentsArray;
|
||||
entries: EntriesArray;
|
||||
itemId: ItemId;
|
||||
listId: ListId;
|
||||
namespaceType: NamespaceType;
|
||||
name: Name;
|
||||
osTypes: OsTypeArray;
|
||||
description: Description;
|
||||
meta: MetaOrUndefined;
|
||||
tags: Tags;
|
||||
|
@ -130,19 +128,18 @@ export interface CreateExceptionListItemOptions {
|
|||
}
|
||||
|
||||
export interface CreateEndpointListItemOptions {
|
||||
_tags: _Tags;
|
||||
comments: CreateCommentsArray;
|
||||
entries: EntriesArray;
|
||||
itemId: ItemId;
|
||||
name: Name;
|
||||
description: Description;
|
||||
meta: MetaOrUndefined;
|
||||
osTypes: OsTypeArray;
|
||||
tags: Tags;
|
||||
type: ExceptionListItemType;
|
||||
}
|
||||
|
||||
export interface UpdateExceptionListItemOptions {
|
||||
_tags: _TagsOrUndefined;
|
||||
_version: _VersionOrUndefined;
|
||||
comments: UpdateCommentsArray;
|
||||
entries: EntriesArray;
|
||||
|
@ -150,6 +147,7 @@ export interface UpdateExceptionListItemOptions {
|
|||
itemId: ItemIdOrUndefined;
|
||||
namespaceType: NamespaceType;
|
||||
name: NameOrUndefined;
|
||||
osTypes: OsTypeArray;
|
||||
description: DescriptionOrUndefined;
|
||||
meta: MetaOrUndefined;
|
||||
tags: TagsOrUndefined;
|
||||
|
@ -157,13 +155,13 @@ export interface UpdateExceptionListItemOptions {
|
|||
}
|
||||
|
||||
export interface UpdateEndpointListItemOptions {
|
||||
_tags: _TagsOrUndefined;
|
||||
_version: _VersionOrUndefined;
|
||||
comments: UpdateCommentsArray;
|
||||
entries: EntriesArray;
|
||||
id: IdOrUndefined;
|
||||
itemId: ItemIdOrUndefined;
|
||||
name: NameOrUndefined;
|
||||
osTypes: OsTypeArray;
|
||||
description: DescriptionOrUndefined;
|
||||
meta: MetaOrUndefined;
|
||||
tags: TagsOrUndefined;
|
||||
|
|
|
@ -16,9 +16,9 @@ import {
|
|||
MetaOrUndefined,
|
||||
NameOrUndefined,
|
||||
NamespaceType,
|
||||
OsTypeArray,
|
||||
TagsOrUndefined,
|
||||
VersionOrUndefined,
|
||||
_TagsOrUndefined,
|
||||
_VersionOrUndefined,
|
||||
} from '../../../common/schemas';
|
||||
|
||||
|
@ -27,12 +27,12 @@ import { getExceptionList } from './get_exception_list';
|
|||
|
||||
interface UpdateExceptionListOptions {
|
||||
id: IdOrUndefined;
|
||||
_tags: _TagsOrUndefined;
|
||||
_version: _VersionOrUndefined;
|
||||
name: NameOrUndefined;
|
||||
description: DescriptionOrUndefined;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
namespaceType: NamespaceType;
|
||||
osTypes: OsTypeArray;
|
||||
listId: ListIdOrUndefined;
|
||||
meta: MetaOrUndefined;
|
||||
user: string;
|
||||
|
@ -43,7 +43,6 @@ interface UpdateExceptionListOptions {
|
|||
}
|
||||
|
||||
export const updateExceptionList = async ({
|
||||
_tags,
|
||||
_version,
|
||||
id,
|
||||
savedObjectsClient,
|
||||
|
@ -67,7 +66,6 @@ export const updateExceptionList = async ({
|
|||
savedObjectType,
|
||||
exceptionList.id,
|
||||
{
|
||||
_tags,
|
||||
description,
|
||||
meta,
|
||||
name,
|
||||
|
|
|
@ -17,9 +17,9 @@ import {
|
|||
MetaOrUndefined,
|
||||
NameOrUndefined,
|
||||
NamespaceType,
|
||||
OsTypeArray,
|
||||
TagsOrUndefined,
|
||||
UpdateCommentsArrayOrUndefined,
|
||||
_TagsOrUndefined,
|
||||
_VersionOrUndefined,
|
||||
} from '../../../common/schemas';
|
||||
|
||||
|
@ -33,13 +33,13 @@ import { getExceptionListItem } from './get_exception_list_item';
|
|||
interface UpdateExceptionListItemOptions {
|
||||
id: IdOrUndefined;
|
||||
comments: UpdateCommentsArrayOrUndefined;
|
||||
_tags: _TagsOrUndefined;
|
||||
_version: _VersionOrUndefined;
|
||||
name: NameOrUndefined;
|
||||
description: DescriptionOrUndefined;
|
||||
entries: EntriesArray;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
namespaceType: NamespaceType;
|
||||
osTypes: OsTypeArray;
|
||||
itemId: ItemIdOrUndefined;
|
||||
meta: MetaOrUndefined;
|
||||
user: string;
|
||||
|
@ -49,7 +49,6 @@ interface UpdateExceptionListItemOptions {
|
|||
}
|
||||
|
||||
export const updateExceptionListItem = async ({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
entries,
|
||||
|
@ -57,6 +56,7 @@ export const updateExceptionListItem = async ({
|
|||
savedObjectsClient,
|
||||
namespaceType,
|
||||
name,
|
||||
osTypes,
|
||||
description,
|
||||
itemId,
|
||||
meta,
|
||||
|
@ -83,12 +83,12 @@ export const updateExceptionListItem = async ({
|
|||
savedObjectType,
|
||||
exceptionListItem.id,
|
||||
{
|
||||
_tags,
|
||||
comments: transformedComments,
|
||||
description,
|
||||
entries,
|
||||
meta,
|
||||
name,
|
||||
os_types: osTypes,
|
||||
tags,
|
||||
type,
|
||||
updated_by: user,
|
||||
|
|
|
@ -71,7 +71,6 @@ export const transformSavedObjectToExceptionList = ({
|
|||
version: _version,
|
||||
attributes: {
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
_tags,
|
||||
created_at,
|
||||
created_by,
|
||||
description,
|
||||
|
@ -79,6 +78,7 @@ export const transformSavedObjectToExceptionList = ({
|
|||
list_id,
|
||||
meta,
|
||||
name,
|
||||
os_types,
|
||||
tags,
|
||||
tie_breaker_id,
|
||||
type,
|
||||
|
@ -93,7 +93,6 @@ export const transformSavedObjectToExceptionList = ({
|
|||
// TODO: Change this to do a decode and throw if the saved object is not as expected.
|
||||
// TODO: Do a throw if after the decode this is not the correct "list_type: list"
|
||||
return {
|
||||
_tags,
|
||||
_version,
|
||||
created_at,
|
||||
created_by,
|
||||
|
@ -104,6 +103,7 @@ export const transformSavedObjectToExceptionList = ({
|
|||
meta,
|
||||
name,
|
||||
namespace_type: getExceptionListType({ savedObjectType: savedObject.type }),
|
||||
os_types,
|
||||
tags,
|
||||
tie_breaker_id,
|
||||
type: exceptionListType.is(type) ? type : 'detection',
|
||||
|
@ -124,11 +124,11 @@ export const transformSavedObjectUpdateToExceptionList = ({
|
|||
const {
|
||||
version: _version,
|
||||
attributes: {
|
||||
_tags,
|
||||
description,
|
||||
immutable,
|
||||
meta,
|
||||
name,
|
||||
os_types: osTypes,
|
||||
tags,
|
||||
type,
|
||||
updated_by: updatedBy,
|
||||
|
@ -141,7 +141,6 @@ export const transformSavedObjectUpdateToExceptionList = ({
|
|||
// TODO: Change this to do a decode and throw if the saved object is not as expected.
|
||||
// TODO: Do a throw if after the decode this is not the correct "list_type: list"
|
||||
return {
|
||||
_tags: _tags ?? exceptionList._tags,
|
||||
_version,
|
||||
created_at: exceptionList.created_at,
|
||||
created_by: exceptionList.created_by,
|
||||
|
@ -152,6 +151,7 @@ export const transformSavedObjectUpdateToExceptionList = ({
|
|||
meta: meta ?? exceptionList.meta,
|
||||
name: name ?? exceptionList.name,
|
||||
namespace_type: getExceptionListType({ savedObjectType: savedObject.type }),
|
||||
os_types: osTypes ?? exceptionList.os_types,
|
||||
tags: tags ?? exceptionList.tags,
|
||||
tie_breaker_id: exceptionList.tie_breaker_id,
|
||||
type: exceptionListType.is(type) ? type : exceptionList.type,
|
||||
|
@ -171,7 +171,6 @@ export const transformSavedObjectToExceptionListItem = ({
|
|||
version: _version,
|
||||
attributes: {
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
_tags,
|
||||
comments,
|
||||
created_at,
|
||||
created_by,
|
||||
|
@ -181,6 +180,7 @@ export const transformSavedObjectToExceptionListItem = ({
|
|||
list_id,
|
||||
meta,
|
||||
name,
|
||||
os_types,
|
||||
tags,
|
||||
tie_breaker_id,
|
||||
type,
|
||||
|
@ -194,7 +194,6 @@ export const transformSavedObjectToExceptionListItem = ({
|
|||
// TODO: Do a throw if after the decode this is not the correct "list_type: item"
|
||||
// TODO: Do a throw if item_id or entries is not defined.
|
||||
return {
|
||||
_tags,
|
||||
_version,
|
||||
comments: comments ?? [],
|
||||
created_at,
|
||||
|
@ -207,6 +206,7 @@ export const transformSavedObjectToExceptionListItem = ({
|
|||
meta,
|
||||
name,
|
||||
namespace_type: getExceptionListType({ savedObjectType: savedObject.type }),
|
||||
os_types,
|
||||
tags,
|
||||
tie_breaker_id,
|
||||
type: exceptionListItemType.is(type) ? type : 'simple',
|
||||
|
@ -226,12 +226,12 @@ export const transformSavedObjectUpdateToExceptionListItem = ({
|
|||
const {
|
||||
version: _version,
|
||||
attributes: {
|
||||
_tags,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
meta,
|
||||
name,
|
||||
os_types: osTypes,
|
||||
tags,
|
||||
type,
|
||||
updated_by: updatedBy,
|
||||
|
@ -245,7 +245,6 @@ export const transformSavedObjectUpdateToExceptionListItem = ({
|
|||
// TODO: Update exception list and item types (perhaps separating out) so as to avoid
|
||||
// defaulting
|
||||
return {
|
||||
_tags: _tags ?? exceptionListItem._tags,
|
||||
_version,
|
||||
comments: comments ?? exceptionListItem.comments,
|
||||
created_at: exceptionListItem.created_at,
|
||||
|
@ -258,6 +257,7 @@ export const transformSavedObjectUpdateToExceptionListItem = ({
|
|||
meta: meta ?? exceptionListItem.meta,
|
||||
name: name ?? exceptionListItem.name,
|
||||
namespace_type: getExceptionListType({ savedObjectType: savedObject.type }),
|
||||
os_types: osTypes ?? exceptionListItem.os_types,
|
||||
tags: tags ?? exceptionListItem.tags,
|
||||
tie_breaker_id: exceptionListItem.tie_breaker_id,
|
||||
type: exceptionListItemType.is(type) ? type : exceptionListItem.type,
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
import { DefaultArray } from './default_array';
|
||||
import { pipe } from 'fp-ts/lib/pipeable';
|
||||
import { left } from 'fp-ts/lib/Either';
|
||||
import { foldLeftRight, getPaths } from '../../../test_utils';
|
||||
|
||||
const testSchema = t.keyof({
|
||||
valid: true,
|
||||
also_valid: true,
|
||||
});
|
||||
type TestSchema = t.TypeOf<typeof testSchema>;
|
||||
|
||||
const defaultArraySchema = DefaultArray(testSchema);
|
||||
|
||||
describe('default_array', () => {
|
||||
test('it should validate an empty array', () => {
|
||||
const payload: string[] = [];
|
||||
const decoded = defaultArraySchema.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
expect(message.schema).toEqual(payload);
|
||||
});
|
||||
|
||||
test('it should validate an array of testSchema', () => {
|
||||
const payload: TestSchema[] = ['valid'];
|
||||
const decoded = defaultArraySchema.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
expect(message.schema).toEqual(payload);
|
||||
});
|
||||
|
||||
test('it should validate an array of valid testSchema strings', () => {
|
||||
const payload = ['valid', 'also_valid'];
|
||||
const decoded = defaultArraySchema.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
expect(message.schema).toEqual(payload);
|
||||
});
|
||||
|
||||
test('it should not validate an array with a number', () => {
|
||||
const payload = ['valid', 123];
|
||||
const decoded = defaultArraySchema.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
expect(getPaths(left(message.errors))).toEqual([
|
||||
'Invalid value "123" supplied to "DefaultArray"',
|
||||
]);
|
||||
expect(message.schema).toEqual({});
|
||||
});
|
||||
|
||||
test('it should not validate an array with an invalid string', () => {
|
||||
const payload = ['valid', 'invalid'];
|
||||
const decoded = defaultArraySchema.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
expect(getPaths(left(message.errors))).toEqual([
|
||||
'Invalid value "invalid" supplied to "DefaultArray"',
|
||||
]);
|
||||
expect(message.schema).toEqual({});
|
||||
});
|
||||
|
||||
test('it should return a default array entry', () => {
|
||||
const payload = null;
|
||||
const decoded = defaultArraySchema.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
expect(message.schema).toEqual([]);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { Either } from 'fp-ts/lib/Either';
|
||||
|
||||
/**
|
||||
* Types the DefaultArray<C> as:
|
||||
* - If undefined, then a default array will be set
|
||||
* - If an array is sent in, then the array will be validated to ensure all elements are type C
|
||||
*/
|
||||
export const DefaultArray = <C extends t.Mixed>(codec: C) => {
|
||||
const arrType = t.array(codec);
|
||||
type ArrType = t.TypeOf<typeof arrType>;
|
||||
return new t.Type<ArrType, ArrType | undefined, unknown>(
|
||||
'DefaultArray',
|
||||
arrType.is,
|
||||
(input, context): Either<t.Errors, ArrType> =>
|
||||
input == null ? t.success([]) : arrType.validate(input, context),
|
||||
t.identity
|
||||
);
|
||||
};
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
export * from './default_actions_array';
|
||||
export * from './default_array';
|
||||
export * from './default_boolean_false';
|
||||
export * from './default_boolean_true';
|
||||
export * from './default_empty_string';
|
||||
|
|
|
@ -76,7 +76,7 @@ describe('When invoking Trusted Apps Schema', () => {
|
|||
os: 'windows',
|
||||
entries: [
|
||||
{
|
||||
field: 'process.executable.text',
|
||||
field: 'process.executable.caseless',
|
||||
type: 'match',
|
||||
operator: 'included',
|
||||
value: 'c:/programs files/Anti-Virus',
|
||||
|
@ -204,7 +204,7 @@ describe('When invoking Trusted Apps Schema', () => {
|
|||
field: 'process.hash.*',
|
||||
value: 'A4370C0CF81686C0B696FA6261c9d3e0d810ae704ab8301839dffd5d5112f476',
|
||||
},
|
||||
{ field: 'process.executable.text', value: '/tmp/dir1' },
|
||||
{ field: 'process.executable.caseless', value: '/tmp/dir1' },
|
||||
].forEach((partialEntry) => {
|
||||
const bodyMsg3 = {
|
||||
...getCreateTrustedAppItem(),
|
||||
|
|
|
@ -35,7 +35,7 @@ export const PostTrustedAppCreateRequestSchema = {
|
|||
schema.object({
|
||||
field: schema.oneOf([
|
||||
schema.literal('process.hash.*'),
|
||||
schema.literal('process.executable.text'),
|
||||
schema.literal('process.executable.caseless'),
|
||||
]),
|
||||
type: schema.literal('match'),
|
||||
operator: schema.literal('included'),
|
||||
|
|
|
@ -33,7 +33,7 @@ export interface PostTrustedAppCreateResponse {
|
|||
}
|
||||
|
||||
export interface MacosLinuxConditionEntry {
|
||||
field: 'process.hash.*' | 'process.executable.text';
|
||||
field: 'process.hash.*' | 'process.executable.caseless';
|
||||
type: 'match';
|
||||
operator: 'included';
|
||||
value: string;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
export { NonEmptyString } from './detection_engine/schemas/types/non_empty_string';
|
||||
export { DefaultArray } from './detection_engine/schemas/types/default_array';
|
||||
export { DefaultUuid } from './detection_engine/schemas/types/default_uuid';
|
||||
export { DefaultStringArray } from './detection_engine/schemas/types/default_string_array';
|
||||
export {
|
||||
|
|
|
@ -42,4 +42,6 @@ export {
|
|||
ExceptionListType,
|
||||
Type,
|
||||
ENDPOINT_LIST_ID,
|
||||
osTypeArray,
|
||||
OsTypeArray,
|
||||
} from '../../lists/common';
|
||||
|
|
|
@ -257,7 +257,7 @@ describe('When the add exception modal is opened', () => {
|
|||
indexPatterns: {
|
||||
...stubIndexPattern,
|
||||
fields: [
|
||||
{ name: 'file.path.text', type: 'string' },
|
||||
{ name: 'file.path.caseless', type: 'string' },
|
||||
{ name: 'subject_name', type: 'string' },
|
||||
{ name: 'trusted', type: 'string' },
|
||||
{ name: 'file.hash.sha256', type: 'string' },
|
||||
|
|
|
@ -30,6 +30,7 @@ import * as i18nCommon from '../../../translations';
|
|||
import * as i18n from './translations';
|
||||
import * as sharedI18n from '../translations';
|
||||
import { Ecs } from '../../../../../common/ecs';
|
||||
import { osTypeArray, OsTypeArray } from '../../../../../common/shared_imports';
|
||||
import { useAppToasts } from '../../../hooks/use_app_toasts';
|
||||
import { useKibana } from '../../../lib/kibana';
|
||||
import { ExceptionBuilderComponent } from '../builder';
|
||||
|
@ -211,12 +212,7 @@ export const AddExceptionModal = memo(function AddExceptionModal({
|
|||
|
||||
const initialExceptionItems = useMemo((): ExceptionsBuilderExceptionItem[] => {
|
||||
if (exceptionListType === 'endpoint' && alertData != null && ruleExceptionList) {
|
||||
return defaultEndpointExceptionItems(
|
||||
exceptionListType,
|
||||
ruleExceptionList.list_id,
|
||||
ruleName,
|
||||
alertData
|
||||
);
|
||||
return defaultEndpointExceptionItems(ruleExceptionList.list_id, ruleName, alertData);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
@ -265,11 +261,11 @@ export const AddExceptionModal = memo(function AddExceptionModal({
|
|||
[setShouldBulkCloseAlert]
|
||||
);
|
||||
|
||||
const retrieveAlertOsTypes = useCallback((): string[] => {
|
||||
const osDefaults = ['windows', 'macos'];
|
||||
const retrieveAlertOsTypes = useCallback((): OsTypeArray => {
|
||||
const osDefaults: OsTypeArray = ['windows', 'macos'];
|
||||
if (alertData != null) {
|
||||
const osTypes = alertData.host && alertData.host.os && alertData.host.os.family;
|
||||
if (osTypes != null && osTypes.length > 0) {
|
||||
if (osTypeArray.is(osTypes) && osTypes != null && osTypes.length > 0) {
|
||||
return osTypes;
|
||||
}
|
||||
return osDefaults;
|
||||
|
@ -316,13 +312,14 @@ export const AddExceptionModal = memo(function AddExceptionModal({
|
|||
[fetchOrCreateListError, exceptionItemsToAdd]
|
||||
);
|
||||
|
||||
const addExceptionMessage =
|
||||
exceptionListType === 'endpoint' ? i18n.ADD_ENDPOINT_EXCEPTION : i18n.ADD_EXCEPTION;
|
||||
|
||||
return (
|
||||
<EuiOverlayMask onClick={onCancel}>
|
||||
<Modal onClose={onCancel} data-test-subj="add-exception-modal">
|
||||
<ModalHeader>
|
||||
<EuiModalHeaderTitle>
|
||||
{exceptionListType === 'endpoint' ? i18n.ADD_ENDPOINT_EXCEPTION : i18n.ADD_EXCEPTION}
|
||||
</EuiModalHeaderTitle>
|
||||
<EuiModalHeaderTitle>{addExceptionMessage}</EuiModalHeaderTitle>
|
||||
<ModalHeaderSubtitle className="eui-textTruncate" title={ruleName}>
|
||||
{ruleName}
|
||||
</ModalHeaderSubtitle>
|
||||
|
@ -429,7 +426,7 @@ export const AddExceptionModal = memo(function AddExceptionModal({
|
|||
isDisabled={isSubmitButtonDisabled}
|
||||
fill
|
||||
>
|
||||
{i18n.ADD_EXCEPTION}
|
||||
{addExceptionMessage}
|
||||
</EuiButton>
|
||||
</EuiModalFooter>
|
||||
)}
|
||||
|
|
|
@ -90,9 +90,9 @@ const getMockNestedParentBuilderEntry = (): FormattedBuilderEntry => ({
|
|||
|
||||
const mockEndpointFields = [
|
||||
{
|
||||
name: 'file.path.text',
|
||||
name: 'file.path.caseless',
|
||||
type: 'string',
|
||||
esTypes: ['text'],
|
||||
esTypes: ['keyword'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
|
@ -303,8 +303,8 @@ describe('Exception builder helpers', () => {
|
|||
{
|
||||
aggregatable: false,
|
||||
count: 0,
|
||||
esTypes: ['text'],
|
||||
name: 'file.path.text',
|
||||
esTypes: ['keyword'],
|
||||
name: 'file.path.caseless',
|
||||
readFromDocValues: false,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
|
|
|
@ -234,13 +234,12 @@ export const ExceptionBuilderComponent = ({
|
|||
// empty `entries` array. Thought about appending an entry item to one, but that
|
||||
// would then be arbitrary, decided to just create a new exception list item
|
||||
const newException = getNewExceptionItem({
|
||||
listType,
|
||||
listId,
|
||||
namespaceType: listNamespaceType,
|
||||
ruleName,
|
||||
});
|
||||
setUpdateExceptions([...exceptions, { ...newException }]);
|
||||
}, [setUpdateExceptions, exceptions, listType, listId, listNamespaceType, ruleName]);
|
||||
}, [setUpdateExceptions, exceptions, listId, listNamespaceType, ruleName]);
|
||||
|
||||
// The builder can have existing exception items, or new exception items that have yet
|
||||
// to be created (and thus lack an id), this was creating some React bugs with relying
|
||||
|
|
|
@ -40,7 +40,6 @@ import { AddExceptionComments } from '../add_exception_comments';
|
|||
import {
|
||||
enrichExistingExceptionItemWithComments,
|
||||
enrichExceptionItemsWithOS,
|
||||
getOperatingSystems,
|
||||
entryHasListType,
|
||||
entryHasNonEcsType,
|
||||
lowercaseHashValues,
|
||||
|
@ -228,8 +227,7 @@ export const EditExceptionModal = memo(function EditExceptionModal({
|
|||
},
|
||||
];
|
||||
if (exceptionListType === 'endpoint') {
|
||||
const osTypes = exceptionItem._tags ? getOperatingSystems(exceptionItem._tags) : [];
|
||||
enriched = lowercaseHashValues(enrichExceptionItemsWithOS(enriched, osTypes));
|
||||
enriched = lowercaseHashValues(enrichExceptionItemsWithOS(enriched, exceptionItem.os_types));
|
||||
}
|
||||
return enriched;
|
||||
}, [exceptionItemsToAdd, exceptionItem, comment, exceptionListType]);
|
||||
|
|
|
@ -6,33 +6,33 @@
|
|||
"Target.process.Ext.code_signature.valid",
|
||||
"Target.process.Ext.services",
|
||||
"Target.process.Ext.user",
|
||||
"Target.process.command_line.text",
|
||||
"Target.process.executable.text",
|
||||
"Target.process.command_line.caseless",
|
||||
"Target.process.executable.caseless",
|
||||
"Target.process.hash.md5",
|
||||
"Target.process.hash.sha1",
|
||||
"Target.process.hash.sha256",
|
||||
"Target.process.hash.sha512",
|
||||
"Target.process.name.text",
|
||||
"Target.process.name.caseless",
|
||||
"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",
|
||||
"Target.process.parent.command_line.text",
|
||||
"Target.process.parent.executable.text",
|
||||
"Target.process.parent.command_line.caseless",
|
||||
"Target.process.parent.executable.caseless",
|
||||
"Target.process.parent.hash.md5",
|
||||
"Target.process.parent.hash.sha1",
|
||||
"Target.process.parent.hash.sha256",
|
||||
"Target.process.parent.hash.sha512",
|
||||
"Target.process.parent.name.text",
|
||||
"Target.process.parent.name.caseless",
|
||||
"Target.process.parent.pgid",
|
||||
"Target.process.parent.working_directory.text",
|
||||
"Target.process.parent.working_directory.caseless",
|
||||
"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.working_directory.text",
|
||||
"Target.process.working_directory.caseless",
|
||||
"agent.id",
|
||||
"agent.type",
|
||||
"agent.version",
|
||||
|
@ -66,14 +66,14 @@
|
|||
"file.mode",
|
||||
"file.name",
|
||||
"file.owner",
|
||||
"file.path.text",
|
||||
"file.path.caseless",
|
||||
"file.pe.company",
|
||||
"file.pe.description",
|
||||
"file.pe.file_version",
|
||||
"file.pe.original_file_name",
|
||||
"file.pe.product",
|
||||
"file.size",
|
||||
"file.target_path.text",
|
||||
"file.target_path.caseless",
|
||||
"file.type",
|
||||
"file.uid",
|
||||
"group.Ext.real.id",
|
||||
|
@ -84,9 +84,9 @@
|
|||
"host.id",
|
||||
"host.os.Ext.variant",
|
||||
"host.os.family",
|
||||
"host.os.full.text",
|
||||
"host.os.full.caseless",
|
||||
"host.os.kernel",
|
||||
"host.os.name.text",
|
||||
"host.os.name.caseless",
|
||||
"host.os.platform",
|
||||
"host.os.version",
|
||||
"host.type",
|
||||
|
@ -96,33 +96,33 @@
|
|||
"process.Ext.code_signature.valid",
|
||||
"process.Ext.services",
|
||||
"process.Ext.user",
|
||||
"process.command_line.text",
|
||||
"process.executable.text",
|
||||
"process.command_line.caseless",
|
||||
"process.executable.caseless",
|
||||
"process.hash.md5",
|
||||
"process.hash.sha1",
|
||||
"process.hash.sha256",
|
||||
"process.hash.sha512",
|
||||
"process.name.text",
|
||||
"process.name.caseless",
|
||||
"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.command_line.text",
|
||||
"process.parent.executable.text",
|
||||
"process.parent.command_line.caseless",
|
||||
"process.parent.executable.caseless",
|
||||
"process.parent.hash.md5",
|
||||
"process.parent.hash.sha1",
|
||||
"process.parent.hash.sha256",
|
||||
"process.parent.hash.sha512",
|
||||
"process.parent.name.text",
|
||||
"process.parent.name.caseless",
|
||||
"process.parent.pgid",
|
||||
"process.parent.working_directory.text",
|
||||
"process.parent.working_directory.caseless",
|
||||
"process.pe.company",
|
||||
"process.pe.description",
|
||||
"process.pe.file_version",
|
||||
"process.pe.original_file_name",
|
||||
"process.pe.product",
|
||||
"process.pgid",
|
||||
"process.working_directory.text",
|
||||
"process.working_directory.caseless",
|
||||
"rule.uuid",
|
||||
"user.domain",
|
||||
"user.email",
|
||||
|
|
|
@ -10,8 +10,6 @@ import moment from 'moment-timezone';
|
|||
import {
|
||||
getOperatorType,
|
||||
getExceptionOperatorSelect,
|
||||
getOperatingSystems,
|
||||
getTagsInclude,
|
||||
getFormattedComments,
|
||||
filterExceptionItems,
|
||||
getNewExceptionItem,
|
||||
|
@ -52,6 +50,7 @@ import {
|
|||
CreateExceptionListItemSchema,
|
||||
ExceptionListItemSchema,
|
||||
EntriesArray,
|
||||
OsTypeArray,
|
||||
} from '../../../../../lists/common/schemas';
|
||||
import { IIndexPattern } from 'src/plugins/data/common';
|
||||
|
||||
|
@ -186,76 +185,18 @@ describe('Exception helpers', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('#getOperatingSystems', () => {
|
||||
test('it returns null if no operating system tag specified', () => {
|
||||
const result = getOperatingSystems(['some tag', 'some other tag']);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
test('it returns null if operating system tag malformed', () => {
|
||||
const result = getOperatingSystems(['some tag', 'jibberos:mac,windows', 'some other tag']);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
test('it returns operating systems if space included in os tag', () => {
|
||||
const result = getOperatingSystems(['some tag', 'os: macos', 'some other tag']);
|
||||
expect(result).toEqual(['macos']);
|
||||
});
|
||||
|
||||
test('it returns operating systems if multiple os tags specified', () => {
|
||||
const result = getOperatingSystems(['some tag', 'os: macos', 'some other tag', 'os:windows']);
|
||||
expect(result).toEqual(['macos', 'windows']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#formatOperatingSystems', () => {
|
||||
test('it returns null if no operating system tag specified', () => {
|
||||
const result = formatOperatingSystems(getOperatingSystems(['some tag', 'some other tag']));
|
||||
|
||||
const result = formatOperatingSystems(['some os', 'some other os']);
|
||||
expect(result).toEqual('');
|
||||
});
|
||||
|
||||
test('it returns null if operating system tag malformed', () => {
|
||||
const result = formatOperatingSystems(
|
||||
getOperatingSystems(['some tag', 'jibberos:mac,windows', 'some other tag'])
|
||||
);
|
||||
|
||||
expect(result).toEqual('');
|
||||
});
|
||||
|
||||
test('it returns formatted operating systems if space included in os tag', () => {
|
||||
const result = formatOperatingSystems(
|
||||
getOperatingSystems(['some tag', 'os: macos', 'some other tag'])
|
||||
);
|
||||
|
||||
expect(result).toEqual('macOS');
|
||||
});
|
||||
|
||||
test('it returns formatted operating systems if multiple os tags specified', () => {
|
||||
const result = formatOperatingSystems(
|
||||
getOperatingSystems(['some tag', 'os: macos', 'some other tag', 'os:windows'])
|
||||
);
|
||||
|
||||
test('it returns formatted operating systems if multiple specified', () => {
|
||||
const result = formatOperatingSystems(['some tag', 'macos', 'some other tag', 'windows']);
|
||||
expect(result).toEqual('macOS, Windows');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getTagsInclude', () => {
|
||||
test('it returns a tuple of "false" and "null" if no matches found', () => {
|
||||
const result = getTagsInclude({ tags: ['some', 'tags', 'here'], regex: /(no match)/ });
|
||||
|
||||
expect(result).toEqual([false, null]);
|
||||
});
|
||||
|
||||
test('it returns a tuple of "true" and matching string if matches found', () => {
|
||||
const result = getTagsInclude({ tags: ['some', 'tags', 'here'], regex: /(some)/ });
|
||||
|
||||
expect(result).toEqual([true, 'some']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getFormattedComments', () => {
|
||||
test('it returns formatted comment object with username and timestamp', () => {
|
||||
const payload = getCommentsArrayMock();
|
||||
|
@ -384,7 +325,6 @@ describe('Exception helpers', () => {
|
|||
|
||||
test('it removes `temporaryId` from items', () => {
|
||||
const { meta, ...rest } = getNewExceptionItem({
|
||||
listType: 'detection',
|
||||
listId: '123',
|
||||
namespaceType: 'single',
|
||||
ruleName: 'rule name',
|
||||
|
@ -400,7 +340,6 @@ describe('Exception helpers', () => {
|
|||
const payload = getExceptionListItemSchemaMock();
|
||||
const result = formatExceptionItemForUpdate(payload);
|
||||
const expected = {
|
||||
_tags: ['endpoint', 'process', 'malware', 'os:linux'],
|
||||
comments: [],
|
||||
description: 'some description',
|
||||
entries: ENTRIES,
|
||||
|
@ -409,6 +348,7 @@ describe('Exception helpers', () => {
|
|||
meta: {},
|
||||
name: 'some name',
|
||||
namespace_type: 'single',
|
||||
os_types: ['linux'],
|
||||
tags: ['user added string for a tag', 'malware'],
|
||||
type: 'simple',
|
||||
};
|
||||
|
@ -489,14 +429,14 @@ describe('Exception helpers', () => {
|
|||
});
|
||||
|
||||
describe('#enrichExceptionItemsWithOS', () => {
|
||||
test('it should add an os tag to an exception item', () => {
|
||||
test('it should add an os to an exception item', () => {
|
||||
const payload = [getExceptionListItemSchemaMock()];
|
||||
const osTypes = ['windows'];
|
||||
const osTypes: OsTypeArray = ['windows'];
|
||||
const result = enrichExceptionItemsWithOS(payload, osTypes);
|
||||
const expected = [
|
||||
{
|
||||
...getExceptionListItemSchemaMock(),
|
||||
_tags: [...getExceptionListItemSchemaMock()._tags, 'os:windows'],
|
||||
os_types: ['windows'],
|
||||
},
|
||||
];
|
||||
expect(result).toEqual(expected);
|
||||
|
@ -504,36 +444,16 @@ describe('Exception helpers', () => {
|
|||
|
||||
test('it should add multiple os tags to all exception items', () => {
|
||||
const payload = [getExceptionListItemSchemaMock(), getExceptionListItemSchemaMock()];
|
||||
const osTypes = ['windows', 'macos'];
|
||||
const osTypes: OsTypeArray = ['windows', 'macos'];
|
||||
const result = enrichExceptionItemsWithOS(payload, osTypes);
|
||||
const expected = [
|
||||
{
|
||||
...getExceptionListItemSchemaMock(),
|
||||
_tags: [...getExceptionListItemSchemaMock()._tags, 'os:windows', 'os:macos'],
|
||||
os_types: ['windows', 'macos'],
|
||||
},
|
||||
{
|
||||
...getExceptionListItemSchemaMock(),
|
||||
_tags: [...getExceptionListItemSchemaMock()._tags, 'os:windows', 'os:macos'],
|
||||
},
|
||||
];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
test('it should add os tag to all exception items without duplication', () => {
|
||||
const payload = [
|
||||
{ ...getExceptionListItemSchemaMock(), _tags: ['os:linux', 'os:windows'] },
|
||||
{ ...getExceptionListItemSchemaMock(), _tags: ['os:linux'] },
|
||||
];
|
||||
const osTypes = ['windows'];
|
||||
const result = enrichExceptionItemsWithOS(payload, osTypes);
|
||||
const expected = [
|
||||
{
|
||||
...getExceptionListItemSchemaMock(),
|
||||
_tags: ['os:linux', 'os:windows'],
|
||||
},
|
||||
{
|
||||
...getExceptionListItemSchemaMock(),
|
||||
_tags: ['os:linux', 'os:windows'],
|
||||
os_types: ['windows', 'macos'],
|
||||
},
|
||||
];
|
||||
expect(result).toEqual(expected);
|
||||
|
@ -715,7 +635,6 @@ describe('Exception helpers', () => {
|
|||
describe('getPrepopulatedItem', () => {
|
||||
test('it returns prepopulated items', () => {
|
||||
const prepopulatedItem = getPrepopulatedItem({
|
||||
listType: 'endpoint',
|
||||
listId: 'some_id',
|
||||
ruleName: 'my rule',
|
||||
codeSignature: { subjectName: '', trusted: '' },
|
||||
|
@ -733,7 +652,7 @@ describe('Exception helpers', () => {
|
|||
field: 'file.Ext.code_signature',
|
||||
type: 'nested',
|
||||
},
|
||||
{ field: 'file.path.text', operator: 'included', type: 'match', value: '' },
|
||||
{ field: 'file.path.caseless', operator: 'included', type: 'match', value: '' },
|
||||
{ field: 'file.hash.sha256', operator: 'included', type: 'match', value: '' },
|
||||
{ field: 'event.code', operator: 'included', type: 'match', value: '' },
|
||||
]);
|
||||
|
@ -741,7 +660,6 @@ describe('Exception helpers', () => {
|
|||
|
||||
test('it returns prepopulated items with values', () => {
|
||||
const prepopulatedItem = getPrepopulatedItem({
|
||||
listType: 'endpoint',
|
||||
listId: 'some_id',
|
||||
ruleName: 'my rule',
|
||||
codeSignature: { subjectName: 'someSubjectName', trusted: 'false' },
|
||||
|
@ -764,7 +682,12 @@ describe('Exception helpers', () => {
|
|||
field: 'file.Ext.code_signature',
|
||||
type: 'nested',
|
||||
},
|
||||
{ field: 'file.path.text', operator: 'included', type: 'match', value: 'some-file-path' },
|
||||
{
|
||||
field: 'file.path.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: 'some-file-path',
|
||||
},
|
||||
{ field: 'file.hash.sha256', operator: 'included', type: 'match', value: 'some-hash' },
|
||||
{ field: 'event.code', operator: 'included', type: 'match', value: 'some-event-code' },
|
||||
]);
|
||||
|
@ -847,7 +770,7 @@ describe('Exception helpers', () => {
|
|||
|
||||
describe('defaultEndpointExceptionItems', () => {
|
||||
test('it should return pre-populated items', () => {
|
||||
const defaultItems = defaultEndpointExceptionItems('endpoint', 'list_id', 'my_rule', {
|
||||
const defaultItems = defaultEndpointExceptionItems('list_id', 'my_rule', {
|
||||
_id: '123',
|
||||
file: {
|
||||
Ext: {
|
||||
|
@ -881,7 +804,7 @@ describe('Exception helpers', () => {
|
|||
type: 'nested',
|
||||
},
|
||||
{
|
||||
field: 'file.path.text',
|
||||
field: 'file.path.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: 'some file path',
|
||||
|
@ -904,7 +827,7 @@ describe('Exception helpers', () => {
|
|||
type: 'nested',
|
||||
},
|
||||
{
|
||||
field: 'file.path.text',
|
||||
field: 'file.path.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: 'some file path',
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import { EuiText, EuiCommentProps, EuiAvatar } from '@elastic/eui';
|
||||
import { capitalize, union } from 'lodash';
|
||||
import { capitalize } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import uuid from 'uuid';
|
||||
|
||||
|
@ -33,8 +33,8 @@ import {
|
|||
createExceptionListItemSchema,
|
||||
exceptionListItemSchema,
|
||||
UpdateExceptionListItemSchema,
|
||||
ExceptionListType,
|
||||
EntryNested,
|
||||
OsTypeArray,
|
||||
} from '../../../shared_imports';
|
||||
import { IIndexPattern } from '../../../../../../../src/plugins/data/common';
|
||||
import { validate } from '../../../../common/validate';
|
||||
|
@ -98,20 +98,12 @@ export const getEntryValue = (item: BuilderEntry): string | string[] | undefined
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the values of tags marked as os
|
||||
*
|
||||
* @param tags an ExceptionItem's tags
|
||||
*/
|
||||
export const getOperatingSystems = (tags: string[]): string[] => {
|
||||
return tags.filter((tag) => tag.startsWith('os:')).map((os) => os.substring(3).trim());
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats os value array to a displayable string
|
||||
*/
|
||||
export const formatOperatingSystems = (osTypes: string[]): string => {
|
||||
return osTypes
|
||||
.filter((os) => ['linux', 'macos', 'windows'].includes(os))
|
||||
.map((os) => {
|
||||
if (os === 'macos') {
|
||||
return 'macOS';
|
||||
|
@ -121,21 +113,6 @@ export const formatOperatingSystems = (osTypes: string[]): string => {
|
|||
.join(', ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all tags that match a given regex
|
||||
*/
|
||||
export const getTagsInclude = ({
|
||||
tags,
|
||||
regex,
|
||||
}: {
|
||||
tags: string[];
|
||||
regex: RegExp;
|
||||
}): [boolean, string | null] => {
|
||||
const matches: string[] | null = tags.join(';').match(regex);
|
||||
const match = matches != null ? matches[1] : null;
|
||||
return [matches != null, match];
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats ExceptionItem.comments into EuiCommentList format
|
||||
*
|
||||
|
@ -158,18 +135,15 @@ export const getFormattedComments = (comments: CommentsArray): EuiCommentProps[]
|
|||
}));
|
||||
|
||||
export const getNewExceptionItem = ({
|
||||
listType,
|
||||
listId,
|
||||
namespaceType,
|
||||
ruleName,
|
||||
}: {
|
||||
listType: ExceptionListType;
|
||||
listId: string;
|
||||
namespaceType: NamespaceType;
|
||||
ruleName: string;
|
||||
}): CreateExceptionListItemBuilderSchema => {
|
||||
return {
|
||||
_tags: [listType],
|
||||
comments: [],
|
||||
description: `${ruleName} - exception list item`,
|
||||
entries: [
|
||||
|
@ -326,14 +300,12 @@ export const enrichExistingExceptionItemWithComments = (
|
|||
*/
|
||||
export const enrichExceptionItemsWithOS = (
|
||||
exceptionItems: Array<ExceptionListItemSchema | CreateExceptionListItemSchema>,
|
||||
osTypes: string[]
|
||||
osTypes: OsTypeArray
|
||||
): Array<ExceptionListItemSchema | CreateExceptionListItemSchema> => {
|
||||
const osTags = osTypes.map((os) => `os:${os}`);
|
||||
return exceptionItems.map((item: ExceptionListItemSchema | CreateExceptionListItemSchema) => {
|
||||
const newTags = item._tags ? union(item._tags, osTags) : [...osTags];
|
||||
return {
|
||||
...item,
|
||||
_tags: newTags,
|
||||
os_types: osTypes,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
@ -419,7 +391,6 @@ export const getCodeSignatureValue = (
|
|||
* Returns the default values from the alert data to autofill new endpoint exceptions
|
||||
*/
|
||||
export const getPrepopulatedItem = ({
|
||||
listType,
|
||||
listId,
|
||||
ruleName,
|
||||
codeSignature,
|
||||
|
@ -428,7 +399,6 @@ export const getPrepopulatedItem = ({
|
|||
eventCode,
|
||||
listNamespace = 'agnostic',
|
||||
}: {
|
||||
listType: ExceptionListType;
|
||||
listId: string;
|
||||
listNamespace?: NamespaceType;
|
||||
ruleName: string;
|
||||
|
@ -438,7 +408,7 @@ export const getPrepopulatedItem = ({
|
|||
eventCode: string;
|
||||
}): ExceptionsBuilderExceptionItem => {
|
||||
return {
|
||||
...getNewExceptionItem({ listType, listId, namespaceType: listNamespace, ruleName }),
|
||||
...getNewExceptionItem({ listId, namespaceType: listNamespace, ruleName }),
|
||||
entries: [
|
||||
{
|
||||
field: 'file.Ext.code_signature',
|
||||
|
@ -459,7 +429,7 @@ export const getPrepopulatedItem = ({
|
|||
],
|
||||
},
|
||||
{
|
||||
field: 'file.path.text',
|
||||
field: 'file.path.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: filePath ?? '',
|
||||
|
@ -514,7 +484,6 @@ export const entryHasNonEcsType = (
|
|||
* Returns the default values from the alert data to autofill new endpoint exceptions
|
||||
*/
|
||||
export const defaultEndpointExceptionItems = (
|
||||
listType: ExceptionListType,
|
||||
listId: string,
|
||||
ruleName: string,
|
||||
alertEcsData: Ecs
|
||||
|
@ -523,7 +492,6 @@ export const defaultEndpointExceptionItems = (
|
|||
|
||||
return getCodeSignatureValue(alertEcsData).map((codeSignature) =>
|
||||
getPrepopulatedItem({
|
||||
listType,
|
||||
listId,
|
||||
ruleName,
|
||||
filePath: file && file.path ? file.path[0] : '',
|
||||
|
|
|
@ -82,7 +82,6 @@ export const useFetchOrCreateRuleExceptionList = ({
|
|||
type: exceptionListType,
|
||||
namespace_type: 'single',
|
||||
list_id: undefined,
|
||||
_tags: undefined,
|
||||
tags: undefined,
|
||||
meta: undefined,
|
||||
};
|
||||
|
|
|
@ -43,7 +43,6 @@ storiesOf('Components/ExceptionItem', module)
|
|||
})
|
||||
.add('with description', () => {
|
||||
const payload = getExceptionListItemSchemaMock();
|
||||
payload._tags = [];
|
||||
payload.comments = [];
|
||||
payload.entries = [
|
||||
{
|
||||
|
@ -66,7 +65,6 @@ storiesOf('Components/ExceptionItem', module)
|
|||
})
|
||||
.add('with comments', () => {
|
||||
const payload = getExceptionListItemSchemaMock();
|
||||
payload._tags = [];
|
||||
payload.description = '';
|
||||
payload.comments = getCommentsArrayMock();
|
||||
payload.entries = [
|
||||
|
@ -90,7 +88,6 @@ storiesOf('Components/ExceptionItem', module)
|
|||
})
|
||||
.add('with nested entries', () => {
|
||||
const payload = getExceptionListItemSchemaMock();
|
||||
payload._tags = [];
|
||||
payload.description = '';
|
||||
payload.comments = [];
|
||||
|
||||
|
|
|
@ -175,10 +175,13 @@ describe('Exception viewer helpers', () => {
|
|||
|
||||
test('it returns formatted description list with a description if one specified', () => {
|
||||
const payload = getExceptionListItemSchemaMock();
|
||||
payload._tags = [];
|
||||
payload.description = 'Im a description';
|
||||
const result = getDescriptionListContent(payload);
|
||||
const expected: DescriptionListItem[] = [
|
||||
{
|
||||
description: 'Linux',
|
||||
title: 'OS',
|
||||
},
|
||||
{
|
||||
description: 'April 20th 2020 @ 15:25:31',
|
||||
title: 'Date created',
|
||||
|
@ -198,10 +201,13 @@ describe('Exception viewer helpers', () => {
|
|||
|
||||
test('it returns just user and date created if no other fields specified', () => {
|
||||
const payload = getExceptionListItemSchemaMock();
|
||||
payload._tags = [];
|
||||
payload.description = '';
|
||||
const result = getDescriptionListContent(payload);
|
||||
const expected: DescriptionListItem[] = [
|
||||
{
|
||||
description: 'Linux',
|
||||
title: 'OS',
|
||||
},
|
||||
{
|
||||
description: 'April 20th 2020 @ 15:25:31',
|
||||
title: 'Date created',
|
||||
|
|
|
@ -6,12 +6,7 @@
|
|||
import moment from 'moment';
|
||||
|
||||
import { entriesNested, ExceptionListItemSchema } from '../../../../lists_plugin_deps';
|
||||
import {
|
||||
getEntryValue,
|
||||
getExceptionOperatorSelect,
|
||||
formatOperatingSystems,
|
||||
getOperatingSystems,
|
||||
} from '../helpers';
|
||||
import { getEntryValue, getExceptionOperatorSelect, formatOperatingSystems } from '../helpers';
|
||||
import { FormattedEntry, BuilderEntry, DescriptionListItem } from '../types';
|
||||
import * as i18n from '../translations';
|
||||
|
||||
|
@ -80,7 +75,7 @@ export const getDescriptionListContent = (
|
|||
const details = [
|
||||
{
|
||||
title: i18n.OPERATING_SYSTEM,
|
||||
value: formatOperatingSystems(getOperatingSystems(exceptionItem._tags ?? [])),
|
||||
value: formatOperatingSystems(exceptionItem.os_types),
|
||||
},
|
||||
{
|
||||
title: i18n.DATE_CREATED,
|
||||
|
|
|
@ -83,7 +83,7 @@ export const ConditionEntry = memo<ConditionEntryProps>(
|
|||
'xpack.securitySolution.trustedapps.logicalConditionBuilder.entry.field.path',
|
||||
{ defaultMessage: 'Path' }
|
||||
),
|
||||
value: 'process.executable.text',
|
||||
value: 'process.executable.caseless',
|
||||
},
|
||||
];
|
||||
}, []);
|
||||
|
|
|
@ -30,7 +30,7 @@ storiesOf('TrustedApps|TrustedAppCard', module)
|
|||
trustedApp.created_at = '2020-09-17T14:52:33.899Z';
|
||||
trustedApp.entries = [
|
||||
{
|
||||
field: 'process.executable.text',
|
||||
field: 'process.executable.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: '/some/path/on/file/system',
|
||||
|
@ -44,7 +44,7 @@ storiesOf('TrustedApps|TrustedAppCard', module)
|
|||
trustedApp.created_at = '2020-09-17T14:52:33.899Z';
|
||||
trustedApp.entries = [
|
||||
{
|
||||
field: 'process.executable.text',
|
||||
field: 'process.executable.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: '/some/path/on/file/system',
|
||||
|
|
|
@ -67,7 +67,7 @@ const generateTrustedAppEntry: (options?: GenerateTrustedAppEntryOptions) => obj
|
|||
return {
|
||||
list_id: ENDPOINT_TRUSTED_APPS_LIST_ID,
|
||||
item_id: `generator_endpoint_trusted_apps_${generateUUID()}`,
|
||||
_tags: ['endpoint', `os:${os}`],
|
||||
os_types: [os],
|
||||
tags: ['user added string for a tag', 'malware'],
|
||||
type: 'simple',
|
||||
description: 'This is a sample agnostic endpoint trusted app entry',
|
||||
|
|
|
@ -62,7 +62,7 @@ describe('buildEventTypeSignal', () => {
|
|||
|
||||
test('it should convert simple fields', async () => {
|
||||
const testEntries: EntriesArray = [
|
||||
{ field: 'server.domain', operator: 'included', type: 'match', value: 'DOMAIN' },
|
||||
{ field: 'host.os.full', operator: 'included', type: 'match', value: 'windows' },
|
||||
{ field: 'server.ip', operator: 'included', type: 'match', value: '192.168.1.1' },
|
||||
{ field: 'host.hostname', operator: 'included', type: 'match', value: 'estc' },
|
||||
];
|
||||
|
@ -71,10 +71,10 @@ describe('buildEventTypeSignal', () => {
|
|||
type: 'simple',
|
||||
entries: [
|
||||
{
|
||||
field: 'server.domain',
|
||||
field: 'host.os.full',
|
||||
operator: 'included',
|
||||
type: 'exact_cased',
|
||||
value: 'DOMAIN',
|
||||
value: 'windows',
|
||||
},
|
||||
{
|
||||
field: 'server.ip',
|
||||
|
@ -108,10 +108,10 @@ describe('buildEventTypeSignal', () => {
|
|||
|
||||
test('it should convert fields case sensitive', async () => {
|
||||
const testEntries: EntriesArray = [
|
||||
{ field: 'server.domain.text', operator: 'included', type: 'match', value: 'DOMAIN' },
|
||||
{ field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' },
|
||||
{ field: 'server.ip', operator: 'included', type: 'match', value: '192.168.1.1' },
|
||||
{
|
||||
field: 'host.hostname.text',
|
||||
field: 'host.hostname.caseless',
|
||||
operator: 'included',
|
||||
type: 'match_any',
|
||||
value: ['estc', 'kibana'],
|
||||
|
@ -122,10 +122,10 @@ describe('buildEventTypeSignal', () => {
|
|||
type: 'simple',
|
||||
entries: [
|
||||
{
|
||||
field: 'server.domain',
|
||||
field: 'host.os.full',
|
||||
operator: 'included',
|
||||
type: 'exact_caseless',
|
||||
value: 'DOMAIN',
|
||||
value: 'windows',
|
||||
},
|
||||
{
|
||||
field: 'server.ip',
|
||||
|
@ -159,12 +159,12 @@ describe('buildEventTypeSignal', () => {
|
|||
|
||||
test('it should deduplicate exception entries', async () => {
|
||||
const testEntries: EntriesArray = [
|
||||
{ field: 'server.domain.text', operator: 'included', type: 'match', value: 'DOMAIN' },
|
||||
{ field: 'server.domain.text', operator: 'included', type: 'match', value: 'DOMAIN' },
|
||||
{ field: 'server.domain.text', operator: 'included', type: 'match', value: 'DOMAIN' },
|
||||
{ field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' },
|
||||
{ field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' },
|
||||
{ field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' },
|
||||
{ field: 'server.ip', operator: 'included', type: 'match', value: '192.168.1.1' },
|
||||
{
|
||||
field: 'host.hostname.text',
|
||||
field: 'host.hostname',
|
||||
operator: 'included',
|
||||
type: 'match_any',
|
||||
value: ['estc', 'kibana'],
|
||||
|
@ -175,10 +175,10 @@ describe('buildEventTypeSignal', () => {
|
|||
type: 'simple',
|
||||
entries: [
|
||||
{
|
||||
field: 'server.domain',
|
||||
field: 'host.os.full',
|
||||
operator: 'included',
|
||||
type: 'exact_caseless',
|
||||
value: 'DOMAIN',
|
||||
value: 'windows',
|
||||
},
|
||||
{
|
||||
field: 'server.ip',
|
||||
|
@ -189,7 +189,7 @@ describe('buildEventTypeSignal', () => {
|
|||
{
|
||||
field: 'host.hostname',
|
||||
operator: 'included',
|
||||
type: 'exact_caseless_any',
|
||||
type: 'exact_cased_any',
|
||||
value: ['estc', 'kibana'],
|
||||
},
|
||||
],
|
||||
|
@ -264,7 +264,7 @@ describe('buildEventTypeSignal', () => {
|
|||
|
||||
test('it should deduplicate exception items', async () => {
|
||||
const testEntries: EntriesArray = [
|
||||
{ field: 'server.domain.text', operator: 'included', type: 'match', value: 'DOMAIN' },
|
||||
{ field: 'host.os.full.caseless', operator: 'included', type: 'match', value: 'windows' },
|
||||
{ field: 'server.ip', operator: 'included', type: 'match', value: '192.168.1.1' },
|
||||
];
|
||||
|
||||
|
@ -272,10 +272,10 @@ describe('buildEventTypeSignal', () => {
|
|||
type: 'simple',
|
||||
entries: [
|
||||
{
|
||||
field: 'server.domain',
|
||||
field: 'host.os.full',
|
||||
operator: 'included',
|
||||
type: 'exact_caseless',
|
||||
value: 'DOMAIN',
|
||||
value: 'windows',
|
||||
},
|
||||
{
|
||||
field: 'server.ip',
|
||||
|
@ -308,9 +308,9 @@ describe('buildEventTypeSignal', () => {
|
|||
test('it should ignore unsupported entries', async () => {
|
||||
// Lists and exists are not supported by the Endpoint
|
||||
const testEntries: EntriesArray = [
|
||||
{ field: 'server.domain', operator: 'included', type: 'match', value: 'DOMAIN' },
|
||||
{ field: 'host.os.full', operator: 'included', type: 'match', value: 'windows' },
|
||||
{
|
||||
field: 'server.domain',
|
||||
field: 'host.os.full',
|
||||
operator: 'included',
|
||||
type: 'list',
|
||||
list: {
|
||||
|
@ -325,10 +325,10 @@ describe('buildEventTypeSignal', () => {
|
|||
type: 'simple',
|
||||
entries: [
|
||||
{
|
||||
field: 'server.domain',
|
||||
field: 'host.os.full',
|
||||
operator: 'included',
|
||||
type: 'exact_cased',
|
||||
value: 'DOMAIN',
|
||||
value: 'windows',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -88,7 +88,7 @@ export async function getFullEndpointExceptionList(
|
|||
const response = await eClient.findExceptionListItem({
|
||||
listId,
|
||||
namespaceType: 'agnostic',
|
||||
filter: `exception-list-agnostic.attributes._tags:\"os:${os}\"`,
|
||||
filter: `exception-list-agnostic.attributes.os_types:\"${os}\"`,
|
||||
perPage: 100,
|
||||
page,
|
||||
sortField: 'created_at',
|
||||
|
@ -141,16 +141,16 @@ export function translateToEndpointExceptions(
|
|||
|
||||
function getMatcherFunction(field: string, matchAny?: boolean): TranslatedEntryMatcher {
|
||||
return matchAny
|
||||
? field.endsWith('.text')
|
||||
? field.endsWith('.caseless')
|
||||
? 'exact_caseless_any'
|
||||
: 'exact_cased_any'
|
||||
: field.endsWith('.text')
|
||||
: field.endsWith('.caseless')
|
||||
? 'exact_caseless'
|
||||
: 'exact_cased';
|
||||
}
|
||||
|
||||
function normalizeFieldName(field: string): string {
|
||||
return field.endsWith('.text') ? field.substring(0, field.length - 5) : field;
|
||||
return field.endsWith('.caseless') ? field.substring(0, field.lastIndexOf('.')) : field;
|
||||
}
|
||||
|
||||
function translateItem(
|
||||
|
|
|
@ -133,7 +133,6 @@ describe('when invoking endpoint trusted apps route handlers', () => {
|
|||
const emptyResponse: FoundExceptionListItemSchema = {
|
||||
data: [
|
||||
{
|
||||
_tags: ['os:windows'],
|
||||
_version: undefined,
|
||||
comments: [],
|
||||
created_at: '2020-09-21T19:43:48.240Z',
|
||||
|
@ -165,6 +164,7 @@ describe('when invoking endpoint trusted apps route handlers', () => {
|
|||
meta: undefined,
|
||||
name: 'test',
|
||||
namespace_type: 'agnostic',
|
||||
os_types: ['windows'],
|
||||
tags: [],
|
||||
tie_breaker_id: '1',
|
||||
type: 'simple',
|
||||
|
@ -240,7 +240,7 @@ describe('when invoking endpoint trusted apps route handlers', () => {
|
|||
os: 'windows',
|
||||
entries: [
|
||||
{
|
||||
field: 'process.executable.text',
|
||||
field: 'process.executable.caseless',
|
||||
type: 'match',
|
||||
operator: 'included',
|
||||
value: 'c:/programs files/Anti-Virus',
|
||||
|
@ -267,6 +267,7 @@ describe('when invoking endpoint trusted apps route handlers', () => {
|
|||
return ({
|
||||
...getExceptionListItemSchemaMock(),
|
||||
...newExceptionItem,
|
||||
os_types: newExceptionItem.osTypes,
|
||||
} as unknown) as ExceptionListItemSchema;
|
||||
});
|
||||
});
|
||||
|
@ -288,12 +289,11 @@ describe('when invoking endpoint trusted apps route handlers', () => {
|
|||
const request = createPostRequest();
|
||||
await routeHandler(context, request, response);
|
||||
expect(exceptionsListClient.createExceptionListItem.mock.calls[0][0]).toEqual({
|
||||
_tags: ['os:windows'],
|
||||
comments: [],
|
||||
description: 'this one is ok',
|
||||
entries: [
|
||||
{
|
||||
field: 'process.executable.text',
|
||||
field: 'process.executable.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: 'c:/programs files/Anti-Virus',
|
||||
|
@ -304,6 +304,7 @@ describe('when invoking endpoint trusted apps route handlers', () => {
|
|||
meta: undefined,
|
||||
name: 'Some Anti-Virus App',
|
||||
namespaceType: 'agnostic',
|
||||
osTypes: ['windows'],
|
||||
tags: [],
|
||||
type: 'simple',
|
||||
});
|
||||
|
@ -320,7 +321,7 @@ describe('when invoking endpoint trusted apps route handlers', () => {
|
|||
description: 'this one is ok',
|
||||
entries: [
|
||||
{
|
||||
field: 'process.executable.text',
|
||||
field: 'process.executable.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: 'c:/programs files/Anti-Virus',
|
||||
|
@ -357,7 +358,7 @@ describe('when invoking endpoint trusted apps route handlers', () => {
|
|||
it('should trim condition entry values', async () => {
|
||||
const newTrustedApp = createNewTrustedAppBody();
|
||||
newTrustedApp.entries.push({
|
||||
field: 'process.executable.text',
|
||||
field: 'process.executable.caseless',
|
||||
value: '\n some value \r\n ',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
|
@ -366,13 +367,13 @@ describe('when invoking endpoint trusted apps route handlers', () => {
|
|||
await routeHandler(context, request, response);
|
||||
expect(exceptionsListClient.createExceptionListItem.mock.calls[0][0].entries).toEqual([
|
||||
{
|
||||
field: 'process.executable.text',
|
||||
field: 'process.executable.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: 'c:/programs files/Anti-Virus',
|
||||
},
|
||||
{
|
||||
field: 'process.executable.text',
|
||||
field: 'process.executable.caseless',
|
||||
value: 'some value',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
|
@ -392,7 +393,7 @@ describe('when invoking endpoint trusted apps route handlers', () => {
|
|||
await routeHandler(context, request, response);
|
||||
expect(exceptionsListClient.createExceptionListItem.mock.calls[0][0].entries).toEqual([
|
||||
{
|
||||
field: 'process.executable.text',
|
||||
field: 'process.executable.caseless',
|
||||
operator: 'included',
|
||||
type: 'match',
|
||||
value: 'c:/programs files/Anti-Virus',
|
||||
|
|
|
@ -20,8 +20,8 @@ export const exceptionItemToTrustedAppItem = (
|
|||
exceptionListItem: ExceptionListItemSchema
|
||||
): TrustedApp => {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { entries, description, created_by, created_at, name, _tags, id } = exceptionListItem;
|
||||
const os = osFromTagsList(_tags);
|
||||
const { entries, description, created_by, created_at, name, os_types, id } = exceptionListItem;
|
||||
const os = os_types.length ? os_types[0] : 'unknown';
|
||||
return {
|
||||
entries: entries.map((entry) => {
|
||||
if (entry.field.startsWith('process.hash')) {
|
||||
|
@ -41,19 +41,6 @@ export const exceptionItemToTrustedAppItem = (
|
|||
} as TrustedApp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the OS entry from a list of tags (property returned with ExcptionListItem).
|
||||
* For Trusted Apps each entry must have at MOST 1 OS.
|
||||
* */
|
||||
const osFromTagsList = (tags: string[]): TrustedApp['os'] | 'unknown' => {
|
||||
for (const tag of tags) {
|
||||
if (tag.startsWith('os:')) {
|
||||
return tag.substr(3) as TrustedApp['os'];
|
||||
}
|
||||
}
|
||||
return 'unknown';
|
||||
};
|
||||
|
||||
export const newTrustedAppItemToExceptionItem = ({
|
||||
os,
|
||||
entries,
|
||||
|
@ -61,7 +48,6 @@ export const newTrustedAppItemToExceptionItem = ({
|
|||
description = '',
|
||||
}: NewTrustedApp): NewExceptionItem => {
|
||||
return {
|
||||
_tags: tagsListFromOs(os),
|
||||
comments: [],
|
||||
description,
|
||||
// @ts-ignore
|
||||
|
@ -83,15 +69,12 @@ export const newTrustedAppItemToExceptionItem = ({
|
|||
meta: undefined,
|
||||
name: name.trim(),
|
||||
namespaceType: 'agnostic',
|
||||
osTypes: [os],
|
||||
tags: [],
|
||||
type: 'simple',
|
||||
};
|
||||
};
|
||||
|
||||
const tagsListFromOs = (os: NewTrustedApp['os']): NewExceptionItem['_tags'] => {
|
||||
return [`os:${os}`];
|
||||
};
|
||||
|
||||
const hashType = (hash: string): 'md5' | 'sha256' | 'sha1' | undefined => {
|
||||
switch (hash.length) {
|
||||
case 32:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue