mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
# Backport This will backport the following commits from `main` to `7.17`: - [Config loader: remove unecessary properties (#154902)](https://github.com/elastic/kibana/pull/154902) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Pierre Gayvallet","email":"pierre.gayvallet@elastic.co"},"sourceCommit":{"committedDate":"2023-04-13T16:16:51Z","message":"Config loader: remove unecessary properties (#154902)\n\n- Updates the logic of `ensureDeepObject` to remove unnecessary\r\nproperties when expanding the object\r\n- We had three versions of this helper, centralized it within `@kbn/std`\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b75d89a2d86c976d60144f8c57b1d415b2f35ac3","branchLabelMapping":{"^v8.8.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Core","release_note:skip","backport:prev-minor","v8.8.0","v8.7.1"],"number":154902,"url":"https://github.com/elastic/kibana/pull/154902","mergeCommit":{"message":"Config loader: remove unecessary properties (#154902)\n\n- Updates the logic of `ensureDeepObject` to remove unnecessary\r\nproperties when expanding the object\r\n- We had three versions of this helper, centralized it within `@kbn/std`\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b75d89a2d86c976d60144f8c57b1d415b2f35ac3"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v8.8.0","labelRegex":"^v8.8.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/154902","number":154902,"mergeCommit":{"message":"Config loader: remove unecessary properties (#154902)\n\n- Updates the logic of `ensureDeepObject` to remove unnecessary\r\nproperties when expanding the object\r\n- We had three versions of this helper, centralized it within `@kbn/std`\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b75d89a2d86c976d60144f8c57b1d415b2f35ac3"}},{"branch":"8.7","label":"v8.7.1","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/155006","number":155006,"state":"MERGED","mergeCommit":{"sha":"d9fbe142bf2a6ca7a3ef7260e2683e26a56ae846","message":"[8.7] Config loader: remove unecessary properties (#154902) (#155006)\n\n# Backport\n\nThis will backport the following commits from `main` to `8.7`:\n- [Config loader: remove unecessary properties\n(#154902)](https://github.com/elastic/kibana/pull/154902)\n\n<!--- Backport version: 8.9.7 -->\n\n### Questions ?\nPlease refer to the [Backport tool\ndocumentation](https://github.com/sqren/backport)\n\n<!--BACKPORT [{\"author\":{\"name\":\"Pierre\nGayvallet\",\"email\":\"pierre.gayvallet@elastic.co\"},\"sourceCommit\":{\"committedDate\":\"2023-04-13T16:16:51Z\",\"message\":\"Config\nloader: remove unecessary properties (#154902)\\n\\n- Updates the logic of\n`ensureDeepObject` to remove unnecessary\\r\\nproperties when expanding\nthe object\\r\\n- We had three versions of this helper, centralized it\nwithin `@kbn/std`\\r\\n\\r\\n---------\\r\\n\\r\\nCo-authored-by: kibanamachine\n<42973632+kibanamachine@users.noreply.github.com>\",\"sha\":\"b75d89a2d86c976d60144f8c57b1d415b2f35ac3\",\"branchLabelMapping\":{\"^v8.8.0$\":\"main\",\"^v(\\\\d+).(\\\\d+).\\\\d+$\":\"$1.$2\"}},\"sourcePullRequest\":{\"labels\":[\"Team:Core\",\"release_note:skip\",\"backport:prev-minor\",\"v8.8.0\"],\"number\":154902,\"url\":\"https://github.com/elastic/kibana/pull/154902\",\"mergeCommit\":{\"message\":\"Config\nloader: remove unecessary properties (#154902)\\n\\n- Updates the logic of\n`ensureDeepObject` to remove unnecessary\\r\\nproperties when expanding\nthe object\\r\\n- We had three versions of this helper, centralized it\nwithin `@kbn/std`\\r\\n\\r\\n---------\\r\\n\\r\\nCo-authored-by: kibanamachine\n<42973632+kibanamachine@users.noreply.github.com>\",\"sha\":\"b75d89a2d86c976d60144f8c57b1d415b2f35ac3\"}},\"sourceBranch\":\"main\",\"suggestedTargetBranches\":[],\"targetPullRequestStates\":[{\"branch\":\"main\",\"label\":\"v8.8.0\",\"labelRegex\":\"^v8.8.0$\",\"isSourceBranch\":true,\"state\":\"MERGED\",\"url\":\"https://github.com/elastic/kibana/pull/154902\",\"number\":154902,\"mergeCommit\":{\"message\":\"Config\nloader: remove unecessary properties (#154902)\\n\\n- Updates the logic of\n`ensureDeepObject` to remove unnecessary\\r\\nproperties when expanding\nthe object\\r\\n- We had three versions of this helper, centralized it\nwithin `@kbn/std`\\r\\n\\r\\n---------\\r\\n\\r\\nCo-authored-by: kibanamachine\n<42973632+kibanamachine@users.noreply.github.com>\",\"sha\":\"b75d89a2d86c976d60144f8c57b1d415b2f35ac3\"}}]}]\nBACKPORT-->\n\nCo-authored-by: Pierre Gayvallet <pierre.gayvallet@elastic.co>"}}]}] BACKPORT--> --------- Co-authored-by: Pierre Gayvallet <pierre.gayvallet@elastic.co> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
20e05372fa
commit
104111b178
14 changed files with 129 additions and 414 deletions
|
@ -28,6 +28,7 @@ NPM_MODULE_EXTRA_FILES = [
|
|||
|
||||
RUNTIME_DEPS = [
|
||||
"//packages/elastic-safer-lodash-set",
|
||||
"//packages/kbn-std",
|
||||
"//packages/kbn-utils",
|
||||
"@npm//js-yaml",
|
||||
"@npm//lodash",
|
||||
|
@ -35,6 +36,7 @@ RUNTIME_DEPS = [
|
|||
|
||||
TYPES_DEPS = [
|
||||
"//packages/elastic-safer-lodash-set",
|
||||
"//packages/kbn-std",
|
||||
"//packages/kbn-utils",
|
||||
"@npm//@elastic/apm-rum",
|
||||
"@npm//@types/jest",
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
const separator = '.';
|
||||
|
||||
/**
|
||||
* Recursively traverses through the object's properties and expands ones with
|
||||
* dot-separated names into nested objects (eg. { a.b: 'c'} -> { a: { b: 'c' }).
|
||||
* @param obj Object to traverse through.
|
||||
* @returns Same object instance with expanded properties.
|
||||
*/
|
||||
export function ensureDeepObject(obj: any): any {
|
||||
if (obj == null || typeof obj !== 'object') {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => ensureDeepObject(item));
|
||||
}
|
||||
|
||||
return Object.keys(obj).reduce((fullObject, propertyKey) => {
|
||||
const propertyValue = obj[propertyKey];
|
||||
if (!propertyKey.includes(separator)) {
|
||||
fullObject[propertyKey] = ensureDeepObject(propertyValue);
|
||||
} else {
|
||||
walk(fullObject, propertyKey.split(separator), propertyValue);
|
||||
}
|
||||
|
||||
return fullObject;
|
||||
}, {} as any);
|
||||
}
|
||||
|
||||
function walk(obj: any, keys: string[], value: any) {
|
||||
const key = keys.shift()!;
|
||||
if (keys.length === 0) {
|
||||
obj[key] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj[key] === undefined) {
|
||||
obj[key] = {};
|
||||
}
|
||||
|
||||
walk(obj[key], keys, ensureDeepObject(value));
|
||||
}
|
|
@ -10,8 +10,8 @@ import { readFileSync } from 'fs';
|
|||
import { safeLoad } from 'js-yaml';
|
||||
|
||||
import { set } from '@elastic/safer-lodash-set';
|
||||
import { ensureDeepObject } from '@kbn/std';
|
||||
import { isPlainObject } from 'lodash';
|
||||
import { ensureDeepObject } from './ensure_deep_object';
|
||||
|
||||
const readYaml = (path: string) => {
|
||||
try {
|
||||
|
|
5
packages/kbn-config/src/__fixtures__/forbidden_1.yml
Normal file
5
packages/kbn-config/src/__fixtures__/forbidden_1.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
test: {
|
||||
"aaa['__proto__.hello']": "Hello",
|
||||
"aaa['__proto__.nested.there']": "There",
|
||||
"aaa['__proto__.nested.here']": "This JS syntax is apparently valid for our parser"
|
||||
}
|
3
packages/kbn-config/src/__fixtures__/forbidden_2.yml
Normal file
3
packages/kbn-config/src/__fixtures__/forbidden_2.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
test:
|
||||
hello:
|
||||
'__proto__.dolly': "Well hello there"
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ensureDeepObject } from './ensure_deep_object';
|
||||
|
||||
test('flat object', () => {
|
||||
const obj = {
|
||||
'foo.a': 1,
|
||||
'foo.b': 2,
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
foo: {
|
||||
a: 1,
|
||||
b: 2,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('deep object', () => {
|
||||
const obj = {
|
||||
foo: {
|
||||
a: 1,
|
||||
b: 2,
|
||||
},
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
foo: {
|
||||
a: 1,
|
||||
b: 2,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('flat within deep object', () => {
|
||||
const obj = {
|
||||
foo: {
|
||||
b: 2,
|
||||
'bar.a': 1,
|
||||
},
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
foo: {
|
||||
b: 2,
|
||||
bar: {
|
||||
a: 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('flat then flat object', () => {
|
||||
const obj = {
|
||||
'foo.bar': {
|
||||
b: 2,
|
||||
'quux.a': 1,
|
||||
},
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
foo: {
|
||||
bar: {
|
||||
b: 2,
|
||||
quux: {
|
||||
a: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('full with empty array', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: [],
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
a: 1,
|
||||
b: [],
|
||||
});
|
||||
});
|
||||
|
||||
test('full with array of primitive values', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: [1, 2, 3],
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
a: 1,
|
||||
b: [1, 2, 3],
|
||||
});
|
||||
});
|
||||
|
||||
test('full with array of full objects', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: [{ c: 2 }, { d: 3 }],
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
a: 1,
|
||||
b: [{ c: 2 }, { d: 3 }],
|
||||
});
|
||||
});
|
||||
|
||||
test('full with array of flat objects', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: [{ 'c.d': 2 }, { 'e.f': 3 }],
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
a: 1,
|
||||
b: [{ c: { d: 2 } }, { e: { f: 3 } }],
|
||||
});
|
||||
});
|
||||
|
||||
test('flat with flat and array of flat objects', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
'b.c': 2,
|
||||
d: [3, { 'e.f': 4 }, { 'g.h': 5 }],
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
a: 1,
|
||||
b: { c: 2 },
|
||||
d: [3, { e: { f: 4 } }, { g: { h: 5 } }],
|
||||
});
|
||||
});
|
||||
|
||||
test('array composed of flat objects', () => {
|
||||
const arr = [{ 'c.d': 2 }, { 'e.f': 3 }];
|
||||
|
||||
expect(ensureDeepObject(arr)).toEqual([{ c: { d: 2 } }, { e: { f: 3 } }]);
|
||||
});
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
const separator = '.';
|
||||
|
||||
/**
|
||||
* Recursively traverses through the object's properties and expands ones with
|
||||
* dot-separated names into nested objects (eg. { a.b: 'c'} -> { a: { b: 'c' }).
|
||||
* @param obj Object to traverse through.
|
||||
* @returns Same object instance with expanded properties.
|
||||
*/
|
||||
export function ensureDeepObject(obj: any): any {
|
||||
if (obj == null || typeof obj !== 'object') {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => ensureDeepObject(item));
|
||||
}
|
||||
|
||||
return Object.keys(obj).reduce((fullObject, propertyKey) => {
|
||||
const propertyValue = obj[propertyKey];
|
||||
if (!propertyKey.includes(separator)) {
|
||||
fullObject[propertyKey] = ensureDeepObject(propertyValue);
|
||||
} else {
|
||||
walk(fullObject, propertyKey.split(separator), propertyValue);
|
||||
}
|
||||
|
||||
return fullObject;
|
||||
}, {} as any);
|
||||
}
|
||||
|
||||
function walk(obj: any, keys: string[], value: any) {
|
||||
const key = keys.shift()!;
|
||||
if (keys.length === 0) {
|
||||
obj[key] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj[key] === undefined) {
|
||||
obj[key] = {};
|
||||
}
|
||||
|
||||
walk(obj[key], keys, ensureDeepObject(value));
|
||||
}
|
|
@ -47,6 +47,18 @@ test('should throw an exception when referenced environment variable in a config
|
|||
).toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
|
||||
test('throws parsing a config with forbidden paths', () => {
|
||||
expect(() =>
|
||||
getConfigFromFiles([fixtureFile('forbidden_1.yml')])
|
||||
).toThrowErrorMatchingInlineSnapshot(`"Forbidden path detected: test.aaa.__proto__.hello"`);
|
||||
});
|
||||
|
||||
test('throws parsing another config with forbidden paths', () => {
|
||||
expect(() =>
|
||||
getConfigFromFiles([fixtureFile('forbidden_2.yml')])
|
||||
).toThrowErrorMatchingInlineSnapshot(`"Forbidden path detected: test.hello.__proto__"`);
|
||||
});
|
||||
|
||||
describe('different cwd()', () => {
|
||||
const originalCwd = process.cwd();
|
||||
const tempCwd = resolve(__dirname);
|
||||
|
|
|
@ -11,7 +11,7 @@ import { safeLoad } from 'js-yaml';
|
|||
|
||||
import { set } from '@elastic/safer-lodash-set';
|
||||
import { isPlainObject } from 'lodash';
|
||||
import { ensureDeepObject } from './ensure_deep_object';
|
||||
import { ensureDeepObject } from '@kbn/std';
|
||||
|
||||
const readYaml = (path: string) => safeLoad(readFileSync(path, 'utf8'));
|
||||
|
||||
|
|
|
@ -143,3 +143,81 @@ test('array composed of flat objects', () => {
|
|||
|
||||
expect(ensureDeepObject(arr)).toEqual([{ c: { d: 2 } }, { e: { f: 3 } }]);
|
||||
});
|
||||
|
||||
describe('forbidden patterns', () => {
|
||||
describe('first pattern', () => {
|
||||
test('throws when finding the first pattern within an object', () => {
|
||||
const obj = {
|
||||
foo: {
|
||||
hello: 'dolly',
|
||||
'bar.__proto__': { yours: 'mine' },
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => ensureDeepObject(obj)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Forbidden path detected: foo.bar.__proto__"`
|
||||
);
|
||||
});
|
||||
|
||||
test('throws when finding the first pattern within an array', () => {
|
||||
const obj = {
|
||||
array: [
|
||||
'hello',
|
||||
{
|
||||
'bar.__proto__': { their: 'mine' },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(() => ensureDeepObject(obj)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Forbidden path detected: array.1.bar.__proto__"`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('second pattern', () => {
|
||||
test('throws when finding the first pattern within an object', () => {
|
||||
const obj = {
|
||||
foo: {
|
||||
hello: 'dolly',
|
||||
'bar.constructor.prototype': { foo: 'bar' },
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => ensureDeepObject(obj)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Forbidden path detected: foo.bar.constructor.prototype"`
|
||||
);
|
||||
});
|
||||
|
||||
test('throws when finding the first pattern within a nested object', () => {
|
||||
const obj = {
|
||||
foo: {
|
||||
hello: 'dolly',
|
||||
'bar.constructor': {
|
||||
main: 'mine',
|
||||
prototype: 'nope',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => ensureDeepObject(obj)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Forbidden path detected: foo.bar.constructor.prototype"`
|
||||
);
|
||||
});
|
||||
|
||||
test('throws when finding the first pattern within an array', () => {
|
||||
const obj = {
|
||||
array: [
|
||||
'hello',
|
||||
{
|
||||
'bar.constructor.prototype': { foo: 'bar' },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(() => ensureDeepObject(obj)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Forbidden path detected: array.1.bar.constructor.prototype"`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -6,56 +6,61 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
//
|
||||
// THIS IS A DIRECT COPY OF
|
||||
// 'packages/kbn-config/src/raw/ensure_deep_object.ts'
|
||||
// BECAUSE THAT IS BLOCKED FOR IMPORTING BY OUR LINTER.
|
||||
//
|
||||
// IF THAT IS EXPOSED, WE SHOULD USE IT RATHER THAN CLONE IT.
|
||||
//
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// ^ Disabling the rule for the entire file because of the complexity to type this
|
||||
|
||||
const FORBIDDEN_PATTERNS = ['__proto__', 'constructor.prototype'];
|
||||
const separator = '.';
|
||||
|
||||
/**
|
||||
* Recursively traverses through the object's properties and expands ones with
|
||||
* dot-separated names into nested objects (eg. { a.b: 'c'} -> { a: { b: 'c' }).
|
||||
* @param obj Object to traverse through.
|
||||
* @param path The current path of the traversal
|
||||
* @returns Same object instance with expanded properties.
|
||||
*/
|
||||
export function ensureDeepObject(obj: any): any {
|
||||
export function ensureDeepObject(obj: any, path: string[] = []): any {
|
||||
assertValidPath(path);
|
||||
|
||||
if (obj == null || typeof obj !== 'object') {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => ensureDeepObject(item));
|
||||
return obj.map((item, index) => ensureDeepObject(item, [...path, `${index}`]));
|
||||
}
|
||||
|
||||
return Object.keys(obj).reduce((fullObject, propertyKey) => {
|
||||
const propertyValue = obj[propertyKey];
|
||||
if (!propertyKey.includes(separator)) {
|
||||
fullObject[propertyKey] = ensureDeepObject(propertyValue);
|
||||
const propertySplits = propertyKey.split(separator);
|
||||
if (propertySplits.length === 1) {
|
||||
fullObject[propertyKey] = ensureDeepObject(propertyValue, [...path, propertyKey]);
|
||||
} else {
|
||||
walk(fullObject, propertyKey.split(separator), propertyValue);
|
||||
walk(fullObject, propertySplits, propertyValue, path);
|
||||
}
|
||||
|
||||
return fullObject;
|
||||
}, {} as any);
|
||||
}
|
||||
|
||||
function walk(obj: any, keys: string[], value: any) {
|
||||
function walk(obj: any, keys: string[], value: any, path: string[]) {
|
||||
assertValidPath([...path, ...keys]);
|
||||
|
||||
const key = keys.shift()!;
|
||||
if (keys.length === 0) {
|
||||
obj[key] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj[key] === undefined) {
|
||||
if (!obj.hasOwnProperty(key)) {
|
||||
obj[key] = {};
|
||||
}
|
||||
|
||||
walk(obj[key], keys, ensureDeepObject(value));
|
||||
walk(obj[key], keys, ensureDeepObject(value, [...path, key, ...keys]), [...path, key]);
|
||||
}
|
||||
|
||||
const assertValidPath = (path: string[]) => {
|
||||
const flat = path.join('.');
|
||||
FORBIDDEN_PATTERNS.forEach((pattern) => {
|
||||
if (flat.includes(pattern)) {
|
||||
throw new Error(`Forbidden path detected: ${flat}`);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -19,6 +19,7 @@ export { isRelativeUrl, modifyUrl, getUrlOrigin } from './url';
|
|||
export { unset } from './unset';
|
||||
export { getFlattenedObject } from './get_flattened_object';
|
||||
export { ensureNoUnsafeProperties } from './ensure_no_unsafe_properties';
|
||||
export { ensureDeepObject } from './ensure_deep_object';
|
||||
export * from './rxjs_7';
|
||||
export {
|
||||
map$,
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ensureDeepObject } from './ensure_deep_object';
|
||||
|
||||
test('flat object', () => {
|
||||
const obj = {
|
||||
'foo.a': 1,
|
||||
'foo.b': 2,
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
foo: {
|
||||
a: 1,
|
||||
b: 2,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('deep object', () => {
|
||||
const obj = {
|
||||
foo: {
|
||||
a: 1,
|
||||
b: 2,
|
||||
},
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
foo: {
|
||||
a: 1,
|
||||
b: 2,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('flat within deep object', () => {
|
||||
const obj = {
|
||||
foo: {
|
||||
b: 2,
|
||||
'bar.a': 1,
|
||||
},
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
foo: {
|
||||
b: 2,
|
||||
bar: {
|
||||
a: 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('flat then flat object', () => {
|
||||
const obj = {
|
||||
'foo.bar': {
|
||||
b: 2,
|
||||
'quux.a': 1,
|
||||
},
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
foo: {
|
||||
bar: {
|
||||
b: 2,
|
||||
quux: {
|
||||
a: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('full with empty array', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: [],
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
a: 1,
|
||||
b: [],
|
||||
});
|
||||
});
|
||||
|
||||
test('full with array of primitive values', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: [1, 2, 3],
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
a: 1,
|
||||
b: [1, 2, 3],
|
||||
});
|
||||
});
|
||||
|
||||
test('full with array of full objects', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: [{ c: 2 }, { d: 3 }],
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
a: 1,
|
||||
b: [{ c: 2 }, { d: 3 }],
|
||||
});
|
||||
});
|
||||
|
||||
test('full with array of flat objects', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
b: [{ 'c.d': 2 }, { 'e.f': 3 }],
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
a: 1,
|
||||
b: [{ c: { d: 2 } }, { e: { f: 3 } }],
|
||||
});
|
||||
});
|
||||
|
||||
test('flat with flat and array of flat objects', () => {
|
||||
const obj = {
|
||||
a: 1,
|
||||
'b.c': 2,
|
||||
d: [3, { 'e.f': 4 }, { 'g.h': 5 }],
|
||||
};
|
||||
|
||||
expect(ensureDeepObject(obj)).toEqual({
|
||||
a: 1,
|
||||
b: { c: 2 },
|
||||
d: [3, { e: { f: 4 } }, { g: { h: 5 } }],
|
||||
});
|
||||
});
|
||||
|
||||
test('array composed of flat objects', () => {
|
||||
const arr = [{ 'c.d': 2 }, { 'e.f': 3 }];
|
||||
|
||||
expect(ensureDeepObject(arr)).toEqual([{ c: { d: 2 } }, { e: { f: 3 } }]);
|
||||
});
|
|
@ -10,14 +10,13 @@ import { accessSync, constants, readFileSync, statSync } from 'fs';
|
|||
import { safeLoad } from 'js-yaml';
|
||||
import { dirname, join } from 'path';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { ensureDeepObject } from '@kbn/std';
|
||||
import type { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
|
||||
import { take } from 'rxjs/operators';
|
||||
import { TelemetryConfigType } from '../../config';
|
||||
|
||||
// look for telemetry.yml in the same places we expect kibana.yml
|
||||
import { ensureDeepObject } from './ensure_deep_object';
|
||||
import { staticTelemetrySchema } from './schema';
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue