From 0e7d0e94dc86ff8f687c3e19ed6d2a57a329d86b Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Sun, 18 Apr 2021 23:07:36 +0200 Subject: [PATCH] Avoid mutating KQL query when validating it (#97081) --- .../service/lib/filter_utils.test.ts | 17 +++++++++++++++++ .../saved_objects/service/lib/filter_utils.ts | 5 +++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/core/server/saved_objects/service/lib/filter_utils.test.ts b/src/core/server/saved_objects/service/lib/filter_utils.test.ts index 956a60b23809d3..2ef5219ccfff16 100644 --- a/src/core/server/saved_objects/service/lib/filter_utils.test.ts +++ b/src/core/server/saved_objects/service/lib/filter_utils.test.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { cloneDeep } from 'lodash'; // @ts-expect-error no ts import { esKuery } from '../../es_query'; @@ -105,6 +106,22 @@ describe('Filter Utils', () => { ) ).toEqual(esKuery.fromKueryExpression('foo.title: "best"')); }); + + test('does not mutate the input KueryNode', () => { + const input = esKuery.nodeTypes.function.buildNode( + 'is', + `foo.attributes.title`, + 'best', + true + ); + + const inputCopy = cloneDeep(input); + + validateConvertFilterToKueryNode(['foo'], input, mockMappings); + + expect(input).toEqual(inputCopy); + }); + test('Validate a simple KQL expression filter', () => { expect( validateConvertFilterToKueryNode(['foo'], 'foo.attributes.title: "best"', mockMappings) diff --git a/src/core/server/saved_objects/service/lib/filter_utils.ts b/src/core/server/saved_objects/service/lib/filter_utils.ts index b3bcef9a62e130..a41a25a27b70dd 100644 --- a/src/core/server/saved_objects/service/lib/filter_utils.ts +++ b/src/core/server/saved_objects/service/lib/filter_utils.ts @@ -7,11 +7,12 @@ */ import { set } from '@elastic/safer-lodash-set'; -import { get } from 'lodash'; +import { get, cloneDeep } from 'lodash'; import { SavedObjectsErrorHelpers } from './errors'; import { IndexMapping } from '../../mappings'; // @ts-expect-error no ts import { esKuery } from '../../es_query'; + type KueryNode = any; const astFunctionType = ['is', 'range', 'nested']; @@ -23,7 +24,7 @@ export const validateConvertFilterToKueryNode = ( ): KueryNode | undefined => { if (filter && indexMapping) { const filterKueryNode = - typeof filter === 'string' ? esKuery.fromKueryExpression(filter) : filter; + typeof filter === 'string' ? esKuery.fromKueryExpression(filter) : cloneDeep(filter); const validationFilterKuery = validateFilterKueryNode({ astFilter: filterKueryNode,