From 13d71b144f72b358df4637e20456218d6482ec8f Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Tue, 21 Jul 2020 13:36:11 -0600 Subject: [PATCH 1/2] Adds version and immutablity data structures so we can eventually utilize immutable lists --- x-pack/plugins/lists/common/constants.mock.ts | 2 ++ .../lists/common/schemas/common/schemas.ts | 12 ++++++++++++ .../index_es_list_schema.mock.ts | 4 ++++ .../elastic_query/index_es_list_schema.ts | 4 ++++ .../search_es_list_schema.mock.ts | 4 ++++ .../elastic_response/search_es_list_schema.ts | 4 ++++ .../create_exception_list_schema.mock.ts | 10 +++++++++- .../request/create_exception_list_schema.ts | 8 +++++++- .../request/create_list_schema.mock.ts | 3 ++- .../schemas/request/create_list_schema.ts | 15 +++++++++++++-- .../schemas/request/patch_list_schema.ts | 12 ++++++++++-- .../request/update_exception_list_schema.ts | 2 ++ .../schemas/request/update_list_schema.ts | 3 ++- .../create_endpoint_list_schema.test.ts | 2 +- .../response/exception_list_schema.mock.ts | 4 ++++ .../schemas/response/exception_list_schema.ts | 4 ++++ .../schemas/response/list_schema.mock.ts | 4 ++++ .../common/schemas/response/list_schema.ts | 4 ++++ .../exceptions_list_so_schema.ts | 7 +++++++ x-pack/plugins/lists/common/shared_imports.ts | 2 ++ .../routes/create_exception_list_route.ts | 3 +++ .../lists/server/routes/create_list_route.ts | 19 ++++++++++++++++--- .../server/routes/import_list_item_route.ts | 2 ++ .../lists/server/routes/patch_list_route.ts | 4 ++-- .../routes/update_exception_list_route.ts | 2 ++ .../lists/server/routes/update_list_route.ts | 4 ++-- .../server/saved_objects/exception_list.ts | 6 ++++++ .../exception_lists/create_endpoint_list.ts | 6 +++++- .../exception_lists/create_exception_list.ts | 8 ++++++++ .../create_exception_list_item.ts | 2 ++ .../exception_lists/exception_list_client.ts | 7 +++++++ .../exception_list_client_types.ts | 6 ++++++ .../exception_lists/update_exception_list.ts | 5 +++++ .../server/services/exception_lists/utils.ts | 18 +++++++++++++++++- .../write_lines_to_bulk_list_items.mock.ts | 2 ++ .../items/write_lines_to_bulk_list_items.ts | 5 +++++ .../server/services/lists/create_list.mock.ts | 4 ++++ .../server/services/lists/create_list.ts | 8 ++++++++ .../lists/create_list_if_it_does_not_exist.ts | 8 ++++++++ .../server/services/lists/list_client.ts | 12 ++++++++++++ .../services/lists/list_client_types.ts | 9 +++++++++ .../server/services/lists/list_mappings.json | 6 ++++++ .../server/services/lists/update_list.mock.ts | 2 ++ .../server/services/lists/update_list.ts | 6 ++++++ .../schemas/types/default_version_number.ts | 2 ++ .../common/shared_exports.ts | 4 ++++ 46 files changed, 252 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/lists/common/constants.mock.ts b/x-pack/plugins/lists/common/constants.mock.ts index 6ed1d19611c68..4f01d43f47ecd 100644 --- a/x-pack/plugins/lists/common/constants.mock.ts +++ b/x-pack/plugins/lists/common/constants.mock.ts @@ -61,3 +61,5 @@ export const COMMENTS = []; export const FILTER = 'name:Nicolas Bourbaki'; export const CURSOR = 'c29tZXN0cmluZ2ZvcnlvdQ=='; export const _VERSION = 'WzI5NywxXQ=='; +export const VERSION = 1; +export const IMMUTABLE = false; diff --git a/x-pack/plugins/lists/common/schemas/common/schemas.ts b/x-pack/plugins/lists/common/schemas/common/schemas.ts index 8f1666bb542d9..26511f89c32b8 100644 --- a/x-pack/plugins/lists/common/schemas/common/schemas.ts +++ b/x-pack/plugins/lists/common/schemas/common/schemas.ts @@ -311,3 +311,15 @@ export type DeserializerOrUndefined = t.TypeOf; export const _version = t.string; export const _versionOrUndefined = t.union([_version, t.undefined]); export type _VersionOrUndefined = t.TypeOf; + +export const version = t.number; +export type Version = t.TypeOf; + +export const versionOrUndefined = t.union([version, t.undefined]); +export type VersionOrUndefined = t.TypeOf; + +export const immutable = t.boolean; +export type Immutable = t.TypeOf; + +export const immutableOrUndefined = t.union([immutable, t.undefined]); +export type ImmutableOrUndefined = t.TypeOf; diff --git a/x-pack/plugins/lists/common/schemas/elastic_query/index_es_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/elastic_query/index_es_list_schema.mock.ts index 85a6b1362a582..81cbaea21d6f6 100644 --- a/x-pack/plugins/lists/common/schemas/elastic_query/index_es_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/elastic_query/index_es_list_schema.mock.ts @@ -8,11 +8,13 @@ import { IndexEsListSchema } from '../../../common/schemas'; import { DATE_NOW, DESCRIPTION, + IMMUTABLE, META, NAME, TIE_BREAKER, TYPE, USER, + VERSION, } from '../../../common/constants.mock'; export const getIndexESListMock = (): IndexEsListSchema => ({ @@ -20,6 +22,7 @@ export const getIndexESListMock = (): IndexEsListSchema => ({ created_by: USER, description: DESCRIPTION, deserializer: undefined, + immutable: IMMUTABLE, meta: META, name: NAME, serializer: undefined, @@ -27,4 +30,5 @@ export const getIndexESListMock = (): IndexEsListSchema => ({ type: TYPE, updated_at: DATE_NOW, updated_by: USER, + version: VERSION, }); diff --git a/x-pack/plugins/lists/common/schemas/elastic_query/index_es_list_schema.ts b/x-pack/plugins/lists/common/schemas/elastic_query/index_es_list_schema.ts index 3ee598291149f..be41e57f99421 100644 --- a/x-pack/plugins/lists/common/schemas/elastic_query/index_es_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/elastic_query/index_es_list_schema.ts @@ -13,6 +13,7 @@ import { created_by, description, deserializerOrUndefined, + immutable, metaOrUndefined, name, serializerOrUndefined, @@ -20,6 +21,7 @@ import { type, updated_at, updated_by, + version, } from '../common/schemas'; export const indexEsListSchema = t.exact( @@ -28,6 +30,7 @@ export const indexEsListSchema = t.exact( created_by, description, deserializer: deserializerOrUndefined, + immutable, meta: metaOrUndefined, name, serializer: serializerOrUndefined, @@ -35,6 +38,7 @@ export const indexEsListSchema = t.exact( type, updated_at, updated_by, + version, }) ); diff --git a/x-pack/plugins/lists/common/schemas/elastic_response/search_es_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/elastic_response/search_es_list_schema.mock.ts index 703d0d0f654a8..1562a2192a173 100644 --- a/x-pack/plugins/lists/common/schemas/elastic_response/search_es_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/elastic_response/search_es_list_schema.mock.ts @@ -10,6 +10,7 @@ import { SearchEsListSchema } from '../../../common/schemas'; import { DATE_NOW, DESCRIPTION, + IMMUTABLE, LIST_ID, LIST_INDEX, META, @@ -17,6 +18,7 @@ import { TIE_BREAKER, TYPE, USER, + VERSION, } from '../../../common/constants.mock'; import { getShardMock } from '../../get_shard.mock'; @@ -25,6 +27,7 @@ export const getSearchEsListMock = (): SearchEsListSchema => ({ created_by: USER, description: DESCRIPTION, deserializer: undefined, + immutable: IMMUTABLE, meta: META, name: NAME, serializer: undefined, @@ -32,6 +35,7 @@ export const getSearchEsListMock = (): SearchEsListSchema => ({ type: TYPE, updated_at: DATE_NOW, updated_by: USER, + version: VERSION, }); export const getSearchListMock = (): SearchResponse => ({ diff --git a/x-pack/plugins/lists/common/schemas/elastic_response/search_es_list_schema.ts b/x-pack/plugins/lists/common/schemas/elastic_response/search_es_list_schema.ts index 46005b81ef680..6807201cf18d9 100644 --- a/x-pack/plugins/lists/common/schemas/elastic_response/search_es_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/elastic_response/search_es_list_schema.ts @@ -13,6 +13,7 @@ import { created_by, description, deserializerOrUndefined, + immutable, metaOrUndefined, name, serializerOrUndefined, @@ -20,6 +21,7 @@ import { type, updated_at, updated_by, + version, } from '../common/schemas'; export const searchEsListSchema = t.exact( @@ -28,6 +30,7 @@ export const searchEsListSchema = t.exact( created_by, description, deserializer: deserializerOrUndefined, + immutable, meta: metaOrUndefined, name, serializer: serializerOrUndefined, @@ -35,6 +38,7 @@ export const searchEsListSchema = t.exact( type, updated_at, updated_by, + version, }) ); diff --git a/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.mock.ts index 22a56f7d42b70..d9c0474610369 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.mock.ts @@ -4,7 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { DESCRIPTION, ENDPOINT_TYPE, META, NAME, NAMESPACE_TYPE } from '../../constants.mock'; +import { + DESCRIPTION, + ENDPOINT_TYPE, + META, + NAME, + NAMESPACE_TYPE, + VERSION, +} from '../../constants.mock'; import { CreateExceptionListSchema } from './create_exception_list_schema'; @@ -17,4 +24,5 @@ export const getCreateExceptionListSchemaMock = (): CreateExceptionListSchema => namespace_type: NAMESPACE_TYPE, tags: [], type: ENDPOINT_TYPE, + version: VERSION, }); diff --git a/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.ts b/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.ts index 8f714760621ff..94a4e1588f5ab 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.ts @@ -21,7 +21,11 @@ import { tags, } from '../common/schemas'; import { RequiredKeepUndefined } from '../../types'; -import { DefaultUuid } from '../../siem_common_deps'; +import { + DefaultUuid, + DefaultVersionNumber, + DefaultVersionNumberDecoded, +} from '../../siem_common_deps'; import { NamespaceType } from '../types'; export const createExceptionListSchema = t.intersection([ @@ -39,6 +43,7 @@ export const createExceptionListSchema = t.intersection([ meta, // defaults to undefined if not set during decode namespace_type, // defaults to 'single' 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 }) ), ]); @@ -54,4 +59,5 @@ export type CreateExceptionListSchemaDecoded = Omit< tags: Tags; list_id: ListId; namespace_type: NamespaceType; + version: DefaultVersionNumberDecoded; }; diff --git a/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts index 482fabb3b997f..461890b944bfa 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { DESCRIPTION, LIST_ID, META, NAME, TYPE } from '../../constants.mock'; +import { DESCRIPTION, LIST_ID, META, NAME, TYPE, VERSION } from '../../constants.mock'; import { CreateListSchema } from './create_list_schema'; @@ -16,4 +16,5 @@ export const getCreateListSchemaMock = (): CreateListSchema => ({ name: NAME, serializer: undefined, type: TYPE, + version: VERSION, }); diff --git a/x-pack/plugins/lists/common/schemas/request/create_list_schema.ts b/x-pack/plugins/lists/common/schemas/request/create_list_schema.ts index 38d6167ea63f3..18ed0f42ccd6f 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_list_schema.ts @@ -8,6 +8,7 @@ import * as t from 'io-ts'; import { description, deserializer, id, meta, name, serializer, type } from '../common/schemas'; import { RequiredKeepUndefined } from '../../types'; +import { DefaultVersionNumber, DefaultVersionNumberDecoded } from '../../siem_common_deps'; export const createListSchema = t.intersection([ t.exact( @@ -17,8 +18,18 @@ export const createListSchema = t.intersection([ type, }) ), - t.exact(t.partial({ deserializer, id, meta, serializer })), + t.exact( + t.partial({ + deserializer, // defaults to undefined if not set during decode + id, // defaults to undefined if not set during decode + meta, // defaults to undefined if not set during decode + serializer, // defaults to undefined if not set during decode + version: DefaultVersionNumber, // defaults to a numerical 1 if not set during decode + }) + ), ]); export type CreateListSchema = t.OutputOf; -export type CreateListSchemaDecoded = RequiredKeepUndefined>; +export type CreateListSchemaDecoded = RequiredKeepUndefined< + Omit, 'version'> +> & { version: DefaultVersionNumberDecoded }; diff --git a/x-pack/plugins/lists/common/schemas/request/patch_list_schema.ts b/x-pack/plugins/lists/common/schemas/request/patch_list_schema.ts index e0cd1571afc81..c92abd2e912eb 100644 --- a/x-pack/plugins/lists/common/schemas/request/patch_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/patch_list_schema.ts @@ -8,7 +8,7 @@ import * as t from 'io-ts'; -import { _version, description, id, meta, name } from '../common/schemas'; +import { _version, description, id, meta, name, version } from '../common/schemas'; import { RequiredKeepUndefined } from '../../types'; export const patchListSchema = t.intersection([ @@ -17,7 +17,15 @@ export const patchListSchema = t.intersection([ id, }) ), - t.exact(t.partial({ _version, description, meta, name })), + t.exact( + t.partial({ + _version, // is undefined if not set during decode + description, // is undefined if not set during decode + meta, // is undefined if not set during decode + name, // is undefined if not set during decode + version, // is undefined if not set during decode + }) + ), ]); export type PatchListSchema = t.OutputOf; diff --git a/x-pack/plugins/lists/common/schemas/request/update_exception_list_schema.ts b/x-pack/plugins/lists/common/schemas/request/update_exception_list_schema.ts index 5d7294ae27af2..dd1bc65d18230 100644 --- a/x-pack/plugins/lists/common/schemas/request/update_exception_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/update_exception_list_schema.ts @@ -21,6 +21,7 @@ import { name, namespace_type, tags, + version, } from '../common/schemas'; import { RequiredKeepUndefined } from '../../types'; import { NamespaceType } from '../types'; @@ -42,6 +43,7 @@ export const updateExceptionListSchema = t.intersection([ meta, // defaults to undefined if not set during decode namespace_type, // defaults to 'single' if not set during decode tags, // defaults to empty array if not set during decode + version, // defaults to undefined if not set during decode }) ), ]); diff --git a/x-pack/plugins/lists/common/schemas/request/update_list_schema.ts b/x-pack/plugins/lists/common/schemas/request/update_list_schema.ts index 19a39d362c241..a9778f23f1302 100644 --- a/x-pack/plugins/lists/common/schemas/request/update_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/update_list_schema.ts @@ -8,7 +8,7 @@ import * as t from 'io-ts'; -import { _version, description, id, meta, name } from '../common/schemas'; +import { _version, description, id, meta, name, version } from '../common/schemas'; import { RequiredKeepUndefined } from '../../types'; export const updateListSchema = t.intersection([ @@ -23,6 +23,7 @@ export const updateListSchema = t.intersection([ t.partial({ _version, // defaults to undefined if not set during decode meta, // defaults to undefined if not set during decode + version, // defaults to undefined if not set during decode }) ), ]); diff --git a/x-pack/plugins/lists/common/schemas/response/create_endpoint_list_schema.test.ts b/x-pack/plugins/lists/common/schemas/response/create_endpoint_list_schema.test.ts index 646cc3d97f8ee..5fccaaac22e3a 100644 --- a/x-pack/plugins/lists/common/schemas/response/create_endpoint_list_schema.test.ts +++ b/x-pack/plugins/lists/common/schemas/response/create_endpoint_list_schema.test.ts @@ -41,7 +41,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,meta,{},name,namespace_type,tags,["user added string for a tag","malware"],tie_breaker_id,type,updated_at,updated_by"', + '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"', ]); expect(message.schema).toEqual({}); }); diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts index f790ad9544d53..2655b09631b23 100644 --- a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts @@ -8,9 +8,11 @@ import { DATE_NOW, DESCRIPTION, ENDPOINT_TYPE, + IMMUTABLE, META, TIE_BREAKER, USER, + VERSION, _VERSION, } from '../../constants.mock'; import { ENDPOINT_LIST_ID } from '../..'; @@ -23,6 +25,7 @@ export const getExceptionListSchemaMock = (): ExceptionListSchema => ({ created_by: USER, description: DESCRIPTION, id: '1', + immutable: IMMUTABLE, list_id: ENDPOINT_LIST_ID, meta: META, name: 'Sample Endpoint Exception List', @@ -32,4 +35,5 @@ export const getExceptionListSchemaMock = (): ExceptionListSchema => ({ type: ENDPOINT_TYPE, updated_at: DATE_NOW, updated_by: 'user_name', + version: VERSION, }); diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.ts b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.ts index 11c23bc2ff354..2dbabb0e2bc3b 100644 --- a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.ts @@ -16,6 +16,7 @@ import { description, exceptionListType, id, + immutable, list_id, metaOrUndefined, name, @@ -24,6 +25,7 @@ import { tie_breaker_id, updated_at, updated_by, + version, } from '../common/schemas'; export const exceptionListSchema = t.exact( @@ -34,6 +36,7 @@ export const exceptionListSchema = t.exact( created_by, description, id, + immutable, list_id, meta: metaOrUndefined, name, @@ -43,6 +46,7 @@ export const exceptionListSchema = t.exact( type: exceptionListType, updated_at, updated_by, + version, }) ); diff --git a/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts index 339beddb00f8e..900c7ea4322a3 100644 --- a/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts @@ -8,12 +8,14 @@ import { ListSchema } from '../../../common/schemas'; import { DATE_NOW, DESCRIPTION, + IMMUTABLE, LIST_ID, META, NAME, TIE_BREAKER, TYPE, USER, + VERSION, } from '../../../common/constants.mock'; export const getListResponseMock = (): ListSchema => ({ @@ -23,6 +25,7 @@ export const getListResponseMock = (): ListSchema => ({ description: DESCRIPTION, deserializer: undefined, id: LIST_ID, + immutable: IMMUTABLE, meta: META, name: NAME, serializer: undefined, @@ -30,4 +33,5 @@ export const getListResponseMock = (): ListSchema => ({ type: TYPE, updated_at: DATE_NOW, updated_by: USER, + version: VERSION, }); diff --git a/x-pack/plugins/lists/common/schemas/response/list_schema.ts b/x-pack/plugins/lists/common/schemas/response/list_schema.ts index 7e2bc202a6520..539c6221fcb0f 100644 --- a/x-pack/plugins/lists/common/schemas/response/list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/response/list_schema.ts @@ -15,6 +15,7 @@ import { description, deserializerOrUndefined, id, + immutable, metaOrUndefined, name, serializerOrUndefined, @@ -22,6 +23,7 @@ import { type, updated_at, updated_by, + version, } from '../common/schemas'; export const listSchema = t.exact( @@ -32,6 +34,7 @@ export const listSchema = t.exact( description, deserializer: deserializerOrUndefined, id, + immutable, meta: metaOrUndefined, name, serializer: serializerOrUndefined, @@ -39,6 +42,7 @@ export const listSchema = t.exact( type, updated_at, updated_by, + version, }) ); diff --git a/x-pack/plugins/lists/common/schemas/saved_objects/exceptions_list_so_schema.ts b/x-pack/plugins/lists/common/schemas/saved_objects/exceptions_list_so_schema.ts index 0b61f122463f3..2bd2a51ca8c74 100644 --- a/x-pack/plugins/lists/common/schemas/saved_objects/exceptions_list_so_schema.ts +++ b/x-pack/plugins/lists/common/schemas/saved_objects/exceptions_list_so_schema.ts @@ -16,6 +16,7 @@ import { description, exceptionListItemType, exceptionListType, + immutableOrUndefined, itemIdOrUndefined, list_id, list_type, @@ -24,8 +25,12 @@ import { tags, tie_breaker_id, updated_by, + versionOrUndefined, } from '../common/schemas'; +/** + * Superset saved object of both lists and list items since they share the same saved object type. + */ export const exceptionListSoSchema = t.exact( t.type({ _tags, @@ -34,6 +39,7 @@ export const exceptionListSoSchema = t.exact( created_by, description, entries: entriesArrayOrUndefined, + immutable: immutableOrUndefined, item_id: itemIdOrUndefined, list_id, list_type, @@ -43,6 +49,7 @@ export const exceptionListSoSchema = t.exact( tie_breaker_id, type: t.union([exceptionListType, exceptionListItemType]), updated_by, + version: versionOrUndefined, }) ); diff --git a/x-pack/plugins/lists/common/shared_imports.ts b/x-pack/plugins/lists/common/shared_imports.ts index ad7c24b3db610..e5302b5cd5d88 100644 --- a/x-pack/plugins/lists/common/shared_imports.ts +++ b/x-pack/plugins/lists/common/shared_imports.ts @@ -8,6 +8,8 @@ export { NonEmptyString, DefaultUuid, DefaultStringArray, + DefaultVersionNumber, + DefaultVersionNumberDecoded, exactCheck, getPaths, foldLeftRight, diff --git a/x-pack/plugins/lists/server/routes/create_exception_list_route.ts b/x-pack/plugins/lists/server/routes/create_exception_list_route.ts index 897d82d6a9ba0..fbe9c6ec9d83b 100644 --- a/x-pack/plugins/lists/server/routes/create_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/create_exception_list_route.ts @@ -43,6 +43,7 @@ export const createExceptionListRoute = (router: IRouter): void => { description, list_id: listId, type, + version, } = request.body; const exceptionLists = getExceptionListClient(context); const exceptionList = await exceptionLists.getExceptionList({ @@ -59,12 +60,14 @@ export const createExceptionListRoute = (router: IRouter): void => { const createdList = await exceptionLists.createExceptionList({ _tags, description, + immutable: false, listId, meta, name, namespaceType, tags, type, + version, }); const [validated, errors] = validate(createdList, exceptionListSchema); if (errors != null) { diff --git a/x-pack/plugins/lists/server/routes/create_list_route.ts b/x-pack/plugins/lists/server/routes/create_list_route.ts index ff041699054c9..297dcfc49db34 100644 --- a/x-pack/plugins/lists/server/routes/create_list_route.ts +++ b/x-pack/plugins/lists/server/routes/create_list_route.ts @@ -9,7 +9,7 @@ import { IRouter } from 'kibana/server'; import { LIST_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; import { validate } from '../../common/siem_common_deps'; -import { createListSchema, listSchema } from '../../common/schemas'; +import { CreateListSchemaDecoded, createListSchema, listSchema } from '../../common/schemas'; import { getListClient } from '.'; @@ -21,13 +21,24 @@ export const createListRoute = (router: IRouter): void => { }, path: LIST_URL, validate: { - body: buildRouteValidation(createListSchema), + body: buildRouteValidation( + createListSchema + ), }, }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); try { - const { name, description, deserializer, id, serializer, type, meta } = request.body; + const { + name, + description, + deserializer, + id, + serializer, + type, + meta, + version, + } = request.body; const lists = getListClient(context); const listExists = await lists.getListIndexExists(); if (!listExists) { @@ -49,10 +60,12 @@ export const createListRoute = (router: IRouter): void => { description, deserializer, id, + immutable: false, meta, name, serializer, type, + version, }); const [validated, errors] = validate(list, listSchema); if (errors != null) { diff --git a/x-pack/plugins/lists/server/routes/import_list_item_route.ts b/x-pack/plugins/lists/server/routes/import_list_item_route.ts index 5e88ca0f2569a..1003a0c52a794 100644 --- a/x-pack/plugins/lists/server/routes/import_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/import_list_item_route.ts @@ -55,6 +55,7 @@ export const importListItemRoute = (router: IRouter, config: ConfigType): void = serializer: list.serializer, stream, type: list.type, + version: 1, }); const [validated, errors] = validate(list, listSchema); @@ -71,6 +72,7 @@ export const importListItemRoute = (router: IRouter, config: ConfigType): void = serializer, stream, type, + version: 1, }); if (importedList == null) { return siemResponse.error({ diff --git a/x-pack/plugins/lists/server/routes/patch_list_route.ts b/x-pack/plugins/lists/server/routes/patch_list_route.ts index 681581c6ff6bd..421f1279f2619 100644 --- a/x-pack/plugins/lists/server/routes/patch_list_route.ts +++ b/x-pack/plugins/lists/server/routes/patch_list_route.ts @@ -27,9 +27,9 @@ export const patchListRoute = (router: IRouter): void => { async (context, request, response) => { const siemResponse = buildSiemResponse(response); try { - const { name, description, id, meta, _version } = request.body; + const { name, description, id, meta, _version, version } = request.body; const lists = getListClient(context); - const list = await lists.updateList({ _version, description, id, meta, name }); + const list = await lists.updateList({ _version, description, id, meta, name, version }); if (list == null) { return siemResponse.error({ body: `list id: "${id}" found found`, diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts index 403a9f6db934f..6fcee81ed573f 100644 --- a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts @@ -45,6 +45,7 @@ export const updateExceptionListRoute = (router: IRouter): void => { meta, namespace_type: namespaceType, type, + version, } = request.body; const exceptionLists = getExceptionListClient(context); if (id == null && listId == null) { @@ -64,6 +65,7 @@ export const updateExceptionListRoute = (router: IRouter): void => { namespaceType, tags, type, + version, }); if (list == null) { return siemResponse.error({ diff --git a/x-pack/plugins/lists/server/routes/update_list_route.ts b/x-pack/plugins/lists/server/routes/update_list_route.ts index 78aed23db13fc..6206c0943a8f3 100644 --- a/x-pack/plugins/lists/server/routes/update_list_route.ts +++ b/x-pack/plugins/lists/server/routes/update_list_route.ts @@ -27,9 +27,9 @@ export const updateListRoute = (router: IRouter): void => { async (context, request, response) => { const siemResponse = buildSiemResponse(response); try { - const { name, description, id, meta, _version } = request.body; + const { name, description, id, meta, _version, version } = request.body; const lists = getListClient(context); - const list = await lists.updateList({ _version, description, id, meta, name }); + const list = await lists.updateList({ _version, description, id, meta, name, version }); if (list == null) { return siemResponse.error({ body: `list id: "${id}" found found`, diff --git a/x-pack/plugins/lists/server/saved_objects/exception_list.ts b/x-pack/plugins/lists/server/saved_objects/exception_list.ts index fc04c5e278d64..3bde3545837cf 100644 --- a/x-pack/plugins/lists/server/saved_objects/exception_list.ts +++ b/x-pack/plugins/lists/server/saved_objects/exception_list.ts @@ -30,6 +30,9 @@ export const commonMapping: SavedObjectsType['mappings'] = { description: { type: 'keyword', }, + immutable: { + type: 'boolean', + }, list_id: { type: 'keyword', }, @@ -54,6 +57,9 @@ export const commonMapping: SavedObjectsType['mappings'] = { updated_by: { type: 'keyword', }, + version: { + type: 'keyword', + }, }, }; diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_list.ts b/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_list.ts index b9a0194e20074..b596b831f2d68 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_list.ts @@ -12,7 +12,7 @@ import { ENDPOINT_LIST_ID, ENDPOINT_LIST_NAME, } from '../../../common/constants'; -import { ExceptionListSchema, ExceptionListSoSchema } from '../../../common/schemas'; +import { ExceptionListSchema, ExceptionListSoSchema, Version } from '../../../common/schemas'; import { getSavedObjectType, transformSavedObjectToExceptionList } from './utils'; @@ -20,12 +20,14 @@ interface CreateEndpointListOptions { savedObjectsClient: SavedObjectsClientContract; user: string; tieBreaker?: string; + version: Version; } export const createEndpointList = async ({ savedObjectsClient, user, tieBreaker, + version, }: CreateEndpointListOptions): Promise => { const savedObjectType = getSavedObjectType({ namespaceType: 'agnostic' }); const dateNow = new Date().toISOString(); @@ -39,6 +41,7 @@ export const createEndpointList = async ({ created_by: user, description: ENDPOINT_LIST_DESCRIPTION, entries: undefined, + immutable: false, item_id: undefined, list_id: ENDPOINT_LIST_ID, list_type: 'list', @@ -48,6 +51,7 @@ export const createEndpointList = async ({ tie_breaker_id: tieBreaker ?? uuid.v4(), type: 'endpoint', updated_by: user, + version, }, { // We intentionally hard coding the id so that there can only be one exception list within the space diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts b/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts index 4da74c7df48bf..c8d709ca340ad 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts @@ -12,11 +12,13 @@ import { ExceptionListSchema, ExceptionListSoSchema, ExceptionListType, + Immutable, ListId, MetaOrUndefined, Name, NamespaceType, Tags, + Version, _Tags, } from '../../../common/schemas'; @@ -29,16 +31,19 @@ interface CreateExceptionListOptions { namespaceType: NamespaceType; name: Name; description: Description; + immutable: Immutable; meta: MetaOrUndefined; user: string; tags: Tags; tieBreaker?: string; type: ExceptionListType; + version: Version; } export const createExceptionList = async ({ _tags, listId, + immutable, savedObjectsClient, namespaceType, name, @@ -48,6 +53,7 @@ export const createExceptionList = async ({ tags, tieBreaker, type, + version, }: CreateExceptionListOptions): Promise => { const savedObjectType = getSavedObjectType({ namespaceType }); const dateNow = new Date().toISOString(); @@ -58,6 +64,7 @@ export const createExceptionList = async ({ created_by: user, description, entries: undefined, + immutable, item_id: undefined, list_id: listId, list_type: 'list', @@ -67,6 +74,7 @@ export const createExceptionList = async ({ tie_breaker_id: tieBreaker ?? uuid.v4(), type, updated_by: user, + version, }); return transformSavedObjectToExceptionList({ savedObject }); }; diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts b/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts index 1acc880c851a6..a90ec61aef4af 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts @@ -72,6 +72,7 @@ export const createExceptionListItem = async ({ created_by: user, description, entries, + immutable: undefined, item_id: itemId, list_id: listId, list_type: 'item', @@ -81,6 +82,7 @@ export const createExceptionListItem = async ({ tie_breaker_id: tieBreaker ?? uuid.v4(), type, updated_by: user, + version: undefined, }); return transformSavedObjectToExceptionListItem({ savedObject }); }; diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts index 08b1f517036a9..11302e64b3538 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts @@ -85,6 +85,7 @@ export class ExceptionListClient { return createEndpointList({ savedObjectsClient, user, + version: 1, }); }; @@ -176,17 +177,20 @@ export class ExceptionListClient { public createExceptionList = async ({ _tags, description, + immutable, listId, meta, name, namespaceType, tags, type, + version, }: CreateExceptionListOptions): Promise => { const { savedObjectsClient, user } = this; return createExceptionList({ _tags, description, + immutable, listId, meta, name, @@ -195,6 +199,7 @@ export class ExceptionListClient { tags, type, user, + version, }); }; @@ -209,6 +214,7 @@ export class ExceptionListClient { namespaceType, tags, type, + version, }: UpdateExceptionListOptions): Promise => { const { savedObjectsClient, user } = this; return updateExceptionList({ @@ -224,6 +230,7 @@ export class ExceptionListClient { tags, type, user, + version, }); }; diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts index b972b6564bb8a..51e3a7ee8046f 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts @@ -21,6 +21,7 @@ import { ExceptionListTypeOrUndefined, FilterOrUndefined, IdOrUndefined, + Immutable, ItemId, ItemIdOrUndefined, ListId, @@ -36,6 +37,8 @@ import { Tags, TagsOrUndefined, UpdateCommentsArray, + Version, + VersionOrUndefined, _Tags, _TagsOrUndefined, _VersionOrUndefined, @@ -61,6 +64,8 @@ export interface CreateExceptionListOptions { meta: MetaOrUndefined; tags: Tags; type: ExceptionListType; + immutable: Immutable; + version: Version; } export interface UpdateExceptionListOptions { @@ -74,6 +79,7 @@ export interface UpdateExceptionListOptions { meta: MetaOrUndefined; tags: TagsOrUndefined; type: ExceptionListTypeOrUndefined; + version: VersionOrUndefined; } export interface DeleteExceptionListOptions { diff --git a/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts b/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts index 99c42e56f4888..c26ff1bca4484 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts @@ -17,6 +17,7 @@ import { NameOrUndefined, NamespaceType, TagsOrUndefined, + VersionOrUndefined, _TagsOrUndefined, _VersionOrUndefined, } from '../../../common/schemas'; @@ -38,6 +39,7 @@ interface UpdateExceptionListOptions { tags: TagsOrUndefined; tieBreaker?: string; type: ExceptionListTypeOrUndefined; + version: VersionOrUndefined; } export const updateExceptionList = async ({ @@ -53,12 +55,14 @@ export const updateExceptionList = async ({ user, tags, type, + version, }: UpdateExceptionListOptions): Promise => { const savedObjectType = getSavedObjectType({ namespaceType }); const exceptionList = await getExceptionList({ id, listId, namespaceType, savedObjectsClient }); if (exceptionList == null) { return null; } else { + const calculatedVersion = version == null ? exceptionList.version + 1 : version; const savedObject = await savedObjectsClient.update( savedObjectType, exceptionList.id, @@ -70,6 +74,7 @@ export const updateExceptionList = async ({ tags, type, updated_by: user, + version: calculatedVersion, }, { version: _version, diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils.ts b/x-pack/plugins/lists/server/services/exception_lists/utils.ts index d5e1965efcc89..b168fae741822 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/utils.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/utils.ts @@ -78,6 +78,7 @@ export const transformSavedObjectToExceptionList = ({ created_at, created_by, description, + immutable, list_id, meta, name, @@ -85,6 +86,7 @@ export const transformSavedObjectToExceptionList = ({ tie_breaker_id, type, updated_by, + version, }, id, updated_at: updatedAt, @@ -99,6 +101,7 @@ export const transformSavedObjectToExceptionList = ({ created_by, description, id, + immutable: immutable ?? false, // This should never be undefined for a list (only a list item) list_id, meta, name, @@ -108,6 +111,7 @@ export const transformSavedObjectToExceptionList = ({ type: exceptionListType.is(type) ? type : 'detection', updated_at: updatedAt ?? dateNow, updated_by, + version: version ?? 1, // This should never be undefined for a list (only a list item) }; }; @@ -121,7 +125,17 @@ export const transformSavedObjectUpdateToExceptionList = ({ const dateNow = new Date().toISOString(); const { version: _version, - attributes: { _tags, description, meta, name, tags, type, updated_by: updatedBy }, + attributes: { + _tags, + description, + immutable, + meta, + name, + tags, + type, + updated_by: updatedBy, + version, + }, id, updated_at: updatedAt, } = savedObject; @@ -135,6 +149,7 @@ export const transformSavedObjectUpdateToExceptionList = ({ created_by: exceptionList.created_by, description: description ?? exceptionList.description, id, + immutable: immutable ?? exceptionList.immutable, list_id: exceptionList.list_id, meta: meta ?? exceptionList.meta, name: name ?? exceptionList.name, @@ -144,6 +159,7 @@ export const transformSavedObjectUpdateToExceptionList = ({ type: exceptionListType.is(type) ? type : exceptionList.type, updated_at: updatedAt ?? dateNow, updated_by: updatedBy ?? exceptionList.updated_by, + version: version ?? exceptionList.version, }; }; diff --git a/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.mock.ts b/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.mock.ts index d868351fc4b33..758fabf3d97df 100644 --- a/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.mock.ts +++ b/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.mock.ts @@ -12,6 +12,7 @@ import { META, TYPE, USER, + VERSION, } from '../../../common/constants.mock'; import { getConfigMockDecoded } from '../../config.mock'; @@ -29,6 +30,7 @@ export const getImportListItemsToStreamOptionsMock = (): ImportListItemsToStream stream: new TestReadable(), type: TYPE, user: USER, + version: VERSION, }); export const getWriteBufferToItemsOptionsMock = (): WriteBufferToItemsOptions => ({ diff --git a/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.ts b/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.ts index 2bffe338e9075..c026b247a90a1 100644 --- a/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.ts +++ b/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.ts @@ -16,6 +16,7 @@ import { MetaOrUndefined, SerializerOrUndefined, Type, + Version, } from '../../../common/schemas'; import { ConfigType } from '../../config'; @@ -34,6 +35,7 @@ export interface ImportListItemsToStreamOptions { type: Type; user: string; meta: MetaOrUndefined; + version: Version; } export const importListItemsToStream = ({ @@ -48,6 +50,7 @@ export const importListItemsToStream = ({ type, user, meta, + version, }: ImportListItemsToStreamOptions): Promise => { return new Promise((resolve) => { const readBuffer = new BufferLines({ bufferSize: config.importBufferSize, input: stream }); @@ -62,12 +65,14 @@ export const importListItemsToStream = ({ description: `File uploaded from file system of ${fileNameEmitted}`, deserializer, id: fileNameEmitted, + immutable: false, listIndex, meta, name: fileNameEmitted, serializer, type, user, + version, }); } readBuffer.resume(); diff --git a/x-pack/plugins/lists/server/services/lists/create_list.mock.ts b/x-pack/plugins/lists/server/services/lists/create_list.mock.ts index 84273ff4cf814..befbe095f2d19 100644 --- a/x-pack/plugins/lists/server/services/lists/create_list.mock.ts +++ b/x-pack/plugins/lists/server/services/lists/create_list.mock.ts @@ -9,6 +9,7 @@ import { CreateListOptions } from '../lists'; import { DATE_NOW, DESCRIPTION, + IMMUTABLE, LIST_ID, LIST_INDEX, META, @@ -16,6 +17,7 @@ import { TIE_BREAKER, TYPE, USER, + VERSION, } from '../../../common/constants.mock'; export const getCreateListOptionsMock = (): CreateListOptions => ({ @@ -24,6 +26,7 @@ export const getCreateListOptionsMock = (): CreateListOptions => ({ description: DESCRIPTION, deserializer: undefined, id: LIST_ID, + immutable: IMMUTABLE, listIndex: LIST_INDEX, meta: META, name: NAME, @@ -31,4 +34,5 @@ export const getCreateListOptionsMock = (): CreateListOptions => ({ tieBreaker: TIE_BREAKER, type: TYPE, user: USER, + version: VERSION, }); diff --git a/x-pack/plugins/lists/server/services/lists/create_list.ts b/x-pack/plugins/lists/server/services/lists/create_list.ts index f97399e6dc131..85214ffb27842 100644 --- a/x-pack/plugins/lists/server/services/lists/create_list.ts +++ b/x-pack/plugins/lists/server/services/lists/create_list.ts @@ -13,12 +13,14 @@ import { Description, DeserializerOrUndefined, IdOrUndefined, + Immutable, IndexEsListSchema, ListSchema, MetaOrUndefined, Name, SerializerOrUndefined, Type, + Version, } from '../../../common/schemas'; export interface CreateListOptions { @@ -34,6 +36,8 @@ export interface CreateListOptions { meta: MetaOrUndefined; dateNow?: string; tieBreaker?: string; + immutable: Immutable; + version: Version; } export const createList = async ({ @@ -49,6 +53,8 @@ export const createList = async ({ meta, dateNow, tieBreaker, + immutable, + version, }: CreateListOptions): Promise => { const createdAt = dateNow ?? new Date().toISOString(); const body: IndexEsListSchema = { @@ -56,6 +62,7 @@ export const createList = async ({ created_by: user, description, deserializer, + immutable, meta, name, serializer, @@ -63,6 +70,7 @@ export const createList = async ({ type, updated_at: createdAt, updated_by: user, + version, }; const response = await callCluster('index', { body, diff --git a/x-pack/plugins/lists/server/services/lists/create_list_if_it_does_not_exist.ts b/x-pack/plugins/lists/server/services/lists/create_list_if_it_does_not_exist.ts index 84f5ac0308191..03a59940641c6 100644 --- a/x-pack/plugins/lists/server/services/lists/create_list_if_it_does_not_exist.ts +++ b/x-pack/plugins/lists/server/services/lists/create_list_if_it_does_not_exist.ts @@ -10,11 +10,13 @@ import { Description, DeserializerOrUndefined, Id, + Immutable, ListSchema, MetaOrUndefined, Name, SerializerOrUndefined, Type, + Version, } from '../../../common/schemas'; import { getList } from './get_list'; @@ -27,12 +29,14 @@ export interface CreateListIfItDoesNotExistOptions { deserializer: DeserializerOrUndefined; serializer: SerializerOrUndefined; description: Description; + immutable: Immutable; callCluster: LegacyAPICaller; listIndex: string; user: string; meta: MetaOrUndefined; dateNow?: string; tieBreaker?: string; + version: Version; } export const createListIfItDoesNotExist = async ({ @@ -48,6 +52,8 @@ export const createListIfItDoesNotExist = async ({ serializer, dateNow, tieBreaker, + version, + immutable, }: CreateListIfItDoesNotExistOptions): Promise => { const list = await getList({ callCluster, id, listIndex }); if (list == null) { @@ -57,6 +63,7 @@ export const createListIfItDoesNotExist = async ({ description, deserializer, id, + immutable, listIndex, meta, name, @@ -64,6 +71,7 @@ export const createListIfItDoesNotExist = async ({ tieBreaker, type, user, + version, }); } else { return list; diff --git a/x-pack/plugins/lists/server/services/lists/list_client.ts b/x-pack/plugins/lists/server/services/lists/list_client.ts index 9bece64fa943f..590bfef6625f5 100644 --- a/x-pack/plugins/lists/server/services/lists/list_client.ts +++ b/x-pack/plugins/lists/server/services/lists/list_client.ts @@ -110,11 +110,13 @@ export class ListClient { public createList = async ({ id, deserializer, + immutable, serializer, name, description, type, meta, + version, }: CreateListOptions): Promise => { const { callCluster, user } = this; const listIndex = this.getListIndex(); @@ -123,12 +125,14 @@ export class ListClient { description, deserializer, id, + immutable, listIndex, meta, name, serializer, type, user, + version, }); }; @@ -138,8 +142,10 @@ export class ListClient { serializer, name, description, + immutable, type, meta, + version, }: CreateListIfItDoesNotExistOptions): Promise => { const { callCluster, user } = this; const listIndex = this.getListIndex(); @@ -148,12 +154,14 @@ export class ListClient { description, deserializer, id, + immutable, listIndex, meta, name, serializer, type, user, + version, }); }; @@ -334,6 +342,7 @@ export class ListClient { listId, stream, meta, + version, }: ImportListItemsToStreamOptions): Promise => { const { callCluster, user, config } = this; const listItemIndex = this.getListItemIndex(); @@ -350,6 +359,7 @@ export class ListClient { stream, type, user, + version, }); }; @@ -419,6 +429,7 @@ export class ListClient { name, description, meta, + version, }: UpdateListOptions): Promise => { const { callCluster, user } = this; const listIndex = this.getListIndex(); @@ -431,6 +442,7 @@ export class ListClient { meta, name, user, + version, }); }; diff --git a/x-pack/plugins/lists/server/services/lists/list_client_types.ts b/x-pack/plugins/lists/server/services/lists/list_client_types.ts index 7fa1727be118b..ea983b38c7e5d 100644 --- a/x-pack/plugins/lists/server/services/lists/list_client_types.ts +++ b/x-pack/plugins/lists/server/services/lists/list_client_types.ts @@ -15,6 +15,7 @@ import { Filter, Id, IdOrUndefined, + Immutable, ListId, ListIdOrUndefined, MetaOrUndefined, @@ -26,6 +27,8 @@ import { SortFieldOrUndefined, SortOrderOrUndefined, Type, + Version, + VersionOrUndefined, _VersionOrUndefined, } from '../../../common/schemas'; import { ConfigType } from '../../config'; @@ -52,11 +55,13 @@ export interface DeleteListItemOptions { export interface CreateListOptions { id: IdOrUndefined; deserializer: DeserializerOrUndefined; + immutable: Immutable; serializer: SerializerOrUndefined; name: Name; description: Description; type: Type; meta: MetaOrUndefined; + version: Version; } export interface CreateListIfItDoesNotExistOptions { @@ -67,6 +72,8 @@ export interface CreateListIfItDoesNotExistOptions { description: Description; type: Type; meta: MetaOrUndefined; + version: Version; + immutable: Immutable; } export interface DeleteListItemByValueOptions { @@ -94,6 +101,7 @@ export interface ImportListItemsToStreamOptions { type: Type; stream: Readable; meta: MetaOrUndefined; + version: Version; } export interface CreateListItemOptions { @@ -119,6 +127,7 @@ export interface UpdateListOptions { name: NameOrUndefined; description: DescriptionOrUndefined; meta: MetaOrUndefined; + version: VersionOrUndefined; } export interface GetListItemOptions { diff --git a/x-pack/plugins/lists/server/services/lists/list_mappings.json b/x-pack/plugins/lists/server/services/lists/list_mappings.json index da9cfec18719a..d00b00b6469a3 100644 --- a/x-pack/plugins/lists/server/services/lists/list_mappings.json +++ b/x-pack/plugins/lists/server/services/lists/list_mappings.json @@ -34,6 +34,12 @@ }, "updated_by": { "type": "keyword" + }, + "version": { + "type": "keyword" + }, + "immutable": { + "type": "boolean" } } } diff --git a/x-pack/plugins/lists/server/services/lists/update_list.mock.ts b/x-pack/plugins/lists/server/services/lists/update_list.mock.ts index fc3d63277c5b5..dd33c85aca98f 100644 --- a/x-pack/plugins/lists/server/services/lists/update_list.mock.ts +++ b/x-pack/plugins/lists/server/services/lists/update_list.mock.ts @@ -13,6 +13,7 @@ import { META, NAME, USER, + VERSION, } from '../../../common/constants.mock'; export const getUpdateListOptionsMock = (): UpdateListOptions => ({ @@ -25,4 +26,5 @@ export const getUpdateListOptionsMock = (): UpdateListOptions => ({ meta: META, name: NAME, user: USER, + version: VERSION, }); diff --git a/x-pack/plugins/lists/server/services/lists/update_list.ts b/x-pack/plugins/lists/server/services/lists/update_list.ts index fba57ca744f9d..67d44be2ae1a7 100644 --- a/x-pack/plugins/lists/server/services/lists/update_list.ts +++ b/x-pack/plugins/lists/server/services/lists/update_list.ts @@ -16,6 +16,7 @@ import { MetaOrUndefined, NameOrUndefined, UpdateEsListSchema, + VersionOrUndefined, _VersionOrUndefined, } from '../../../common/schemas'; @@ -31,6 +32,7 @@ export interface UpdateListOptions { description: DescriptionOrUndefined; meta: MetaOrUndefined; dateNow?: string; + version: VersionOrUndefined; } export const updateList = async ({ @@ -43,12 +45,14 @@ export const updateList = async ({ user, meta, dateNow, + version, }: UpdateListOptions): Promise => { const updatedAt = dateNow ?? new Date().toISOString(); const list = await getList({ callCluster, id, listIndex }); if (list == null) { return null; } else { + const calculatedVersion = version == null ? list.version + 1 : version; const doc: UpdateEsListSchema = { description, meta, @@ -70,6 +74,7 @@ export const updateList = async ({ description: description ?? list.description, deserializer: list.deserializer, id: response._id, + immutable: list.immutable, meta, name: name ?? list.name, serializer: list.serializer, @@ -77,6 +82,7 @@ export const updateList = async ({ type: list.type, updated_at: updatedAt, updated_by: user, + version: calculatedVersion, }; } }; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/types/default_version_number.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/default_version_number.ts index bbba7c5b8f3bb..a2f5ca3da1b70 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/types/default_version_number.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/default_version_number.ts @@ -19,3 +19,5 @@ export const DefaultVersionNumber = new t.Type; diff --git a/x-pack/plugins/security_solution/common/shared_exports.ts b/x-pack/plugins/security_solution/common/shared_exports.ts index 1b5b17ef35cae..bd1086a3f21e9 100644 --- a/x-pack/plugins/security_solution/common/shared_exports.ts +++ b/x-pack/plugins/security_solution/common/shared_exports.ts @@ -7,6 +7,10 @@ export { NonEmptyString } from './detection_engine/schemas/types/non_empty_string'; export { DefaultUuid } from './detection_engine/schemas/types/default_uuid'; export { DefaultStringArray } from './detection_engine/schemas/types/default_string_array'; +export { + DefaultVersionNumber, + DefaultVersionNumberDecoded, +} from './detection_engine/schemas/types/default_version_number'; export { exactCheck } from './exact_check'; export { getPaths, foldLeftRight } from './test_utils'; export { validate, validateEither } from './validate'; From ea9ebdf6e6fda2ef3bb4215f30e745c27f26e600 Mon Sep 17 00:00:00 2001 From: FrankHassanabad Date: Tue, 21 Jul 2020 15:09:06 -0600 Subject: [PATCH 2/2] Fixes unit test --- .../common/components/autocomplete/field_value_lists.test.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.test.tsx b/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.test.tsx index 1ff5d770521f3..90e195b6e95a0 100644 --- a/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.test.tsx @@ -15,7 +15,7 @@ import { getField } from '../../../../../../../src/plugins/data/common/index_pat import { ListSchema } from '../../../lists_plugin_deps'; import { getFoundListSchemaMock } from '../../../../../lists/common/schemas/response/found_list_schema.mock'; import { getListResponseMock } from '../../../../../lists/common/schemas/response/list_schema.mock'; -import { DATE_NOW } from '../../../../../lists/common/constants.mock'; +import { DATE_NOW, VERSION, IMMUTABLE } from '../../../../../lists/common/constants.mock'; import { AutocompleteFieldListsComponent } from './field_value_lists'; @@ -221,6 +221,8 @@ describe('AutocompleteFieldListsComponent', () => { type: 'ip', updated_at: DATE_NOW, updated_by: 'some user', + version: VERSION, + immutable: IMMUTABLE, }); }); });