mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* Test config settings that are exposed to the browser (#129438)
(cherry picked from commit 27ff7d3424
)
# Conflicts:
# .github/CODEOWNERS
# packages/kbn-config-schema/src/index.ts
* Enable security plugin in OSS tests
This is a partial backport of #111681, so the Kibana security
plugin is enabled but Elasticsearch security is still disabled.
* Fix exposed config key tests
The exposed config keys are slightly different in the 7.17 branch.
* Fix UI Capabilities tests
The enterpriseSearch plugin does not have a required dependency on
the security plugin in the 7.17 branch, so our bacported
assertions for these tests needed to change accordingly.
This commit is contained in:
parent
923cd73b3b
commit
6ba02ec7d6
30 changed files with 562 additions and 156 deletions
|
@ -38,6 +38,7 @@ import {
|
|||
NullableProps,
|
||||
RecordOfOptions,
|
||||
RecordOfType,
|
||||
SchemaStructureEntry,
|
||||
StringOptions,
|
||||
StringType,
|
||||
Type,
|
||||
|
@ -49,7 +50,7 @@ import {
|
|||
StreamType,
|
||||
} from './types';
|
||||
|
||||
export type { TypeOf, Props, NullableProps };
|
||||
export type { TypeOf, Props, SchemaStructureEntry, NullableProps };
|
||||
export { ObjectType, Type };
|
||||
export { ByteSizeValue } from './byte_size_value';
|
||||
export { SchemaTypeError, ValidationError } from './errors';
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
export type { TypeOptions } from './type';
|
||||
export type { SchemaStructureEntry } from './type';
|
||||
export { Type } from './type';
|
||||
export { AnyType } from './any_type';
|
||||
export type { ArrayOptions } from './array_type';
|
||||
|
|
|
@ -490,3 +490,76 @@ describe('#extends', () => {
|
|||
expect(extended.validate(undefined)).toEqual({ initial: 'bar', added: 42 });
|
||||
});
|
||||
});
|
||||
|
||||
test('returns schema structure', () => {
|
||||
// This test covers different schema types that may or may not be nested
|
||||
const objSchema = schema.object({
|
||||
any: schema.any(),
|
||||
array: schema.arrayOf(schema.string()),
|
||||
boolean: schema.boolean(),
|
||||
buffer: schema.buffer(),
|
||||
byteSize: schema.byteSize(),
|
||||
conditional: schema.conditional(
|
||||
schema.contextRef('context_value_1'),
|
||||
schema.contextRef('context_value_2'),
|
||||
schema.string(),
|
||||
schema.string()
|
||||
),
|
||||
duration: schema.duration(),
|
||||
ip: schema.ip(),
|
||||
literal: schema.literal('foo'),
|
||||
map: schema.mapOf(schema.string(), schema.string()),
|
||||
maybe: schema.maybe(schema.string()),
|
||||
never: schema.never(),
|
||||
nullable: schema.nullable(schema.string()),
|
||||
number: schema.number(),
|
||||
record: schema.recordOf(schema.string(), schema.string()),
|
||||
stream: schema.stream(),
|
||||
string: schema.string(),
|
||||
union: schema.oneOf([schema.string()]),
|
||||
uri: schema.uri(),
|
||||
});
|
||||
const type = objSchema.extends({
|
||||
nested: objSchema,
|
||||
});
|
||||
expect(type.getSchemaStructure()).toEqual([
|
||||
{ path: ['any'], type: 'any' },
|
||||
{ path: ['array'], type: 'array' },
|
||||
{ path: ['boolean'], type: 'boolean' },
|
||||
{ path: ['buffer'], type: 'binary' },
|
||||
{ path: ['byteSize'], type: 'bytes' },
|
||||
{ path: ['conditional'], type: 'any' },
|
||||
{ path: ['duration'], type: 'duration' },
|
||||
{ path: ['ip'], type: 'string' },
|
||||
{ path: ['literal'], type: 'any' },
|
||||
{ path: ['map'], type: 'map' },
|
||||
{ path: ['maybe'], type: 'string' },
|
||||
{ path: ['never'], type: 'any' },
|
||||
{ path: ['nullable'], type: 'alternatives' },
|
||||
{ path: ['number'], type: 'number' },
|
||||
{ path: ['record'], type: 'record' },
|
||||
{ path: ['stream'], type: 'stream' },
|
||||
{ path: ['string'], type: 'string' },
|
||||
{ path: ['union'], type: 'alternatives' },
|
||||
{ path: ['uri'], type: 'string' },
|
||||
{ path: ['nested', 'any'], type: 'any' },
|
||||
{ path: ['nested', 'array'], type: 'array' },
|
||||
{ path: ['nested', 'boolean'], type: 'boolean' },
|
||||
{ path: ['nested', 'buffer'], type: 'binary' },
|
||||
{ path: ['nested', 'byteSize'], type: 'bytes' },
|
||||
{ path: ['nested', 'conditional'], type: 'any' },
|
||||
{ path: ['nested', 'duration'], type: 'duration' },
|
||||
{ path: ['nested', 'ip'], type: 'string' },
|
||||
{ path: ['nested', 'literal'], type: 'any' },
|
||||
{ path: ['nested', 'map'], type: 'map' },
|
||||
{ path: ['nested', 'maybe'], type: 'string' },
|
||||
{ path: ['nested', 'never'], type: 'any' },
|
||||
{ path: ['nested', 'nullable'], type: 'alternatives' },
|
||||
{ path: ['nested', 'number'], type: 'number' },
|
||||
{ path: ['nested', 'record'], type: 'record' },
|
||||
{ path: ['nested', 'stream'], type: 'stream' },
|
||||
{ path: ['nested', 'string'], type: 'string' },
|
||||
{ path: ['nested', 'union'], type: 'alternatives' },
|
||||
{ path: ['nested', 'uri'], type: 'string' },
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -53,6 +53,7 @@ export class StringType extends Type<string> {
|
|||
);
|
||||
}
|
||||
|
||||
schema.type = 'string';
|
||||
super(schema, options);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,11 @@ export interface TypeOptions<T> {
|
|||
validate?: (value: T) => string | void;
|
||||
}
|
||||
|
||||
export interface SchemaStructureEntry {
|
||||
path: string[];
|
||||
type: string;
|
||||
}
|
||||
|
||||
export const convertValidationFunction = <T = unknown>(
|
||||
validate: (value: T) => string | void
|
||||
): CustomValidator<T> => {
|
||||
|
@ -98,6 +103,10 @@ export abstract class Type<V> {
|
|||
return this.internalSchema;
|
||||
}
|
||||
|
||||
public getSchemaStructure() {
|
||||
return recursiveGetSchemaStructure(this.internalSchema);
|
||||
}
|
||||
|
||||
protected handleError(
|
||||
type: string,
|
||||
context: Record<string, any>,
|
||||
|
@ -141,3 +150,17 @@ export abstract class Type<V> {
|
|||
return new SchemaTypeError(message || code, convertedPath);
|
||||
}
|
||||
}
|
||||
|
||||
function recursiveGetSchemaStructure(internalSchema: AnySchema, path: string[] = []) {
|
||||
const array: SchemaStructureEntry[] = [];
|
||||
// Note: we are relying on Joi internals to obtain the schema structure (recursive keys).
|
||||
// This is not ideal, but it works for now and we only need it for some integration test assertions.
|
||||
// If it breaks in the future, we'll need to update our tests.
|
||||
for (const [key, val] of (internalSchema as any)._ids._byKey.entries()) {
|
||||
array.push(...recursiveGetSchemaStructure(val.schema, [...path, key]));
|
||||
}
|
||||
if (!array.length) {
|
||||
array.push({ path, type: internalSchema.type ?? 'unknown' });
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ export class HttpResourcesService implements CoreService<InternalHttpResourcesSe
|
|||
vars: {
|
||||
apmConfig,
|
||||
},
|
||||
includeExposedConfigKeys: options.includeExposedConfigKeys,
|
||||
});
|
||||
|
||||
return response.ok({
|
||||
|
@ -112,6 +113,7 @@ export class HttpResourcesService implements CoreService<InternalHttpResourcesSe
|
|||
vars: {
|
||||
apmConfig,
|
||||
},
|
||||
includeExposedConfigKeys: options.includeExposedConfigKeys,
|
||||
});
|
||||
|
||||
return response.ok({
|
||||
|
|
|
@ -28,6 +28,11 @@ export interface HttpResourcesRenderOptions {
|
|||
* All HTML pages are already pre-configured with `content-security-policy` header that cannot be overridden.
|
||||
* */
|
||||
headers?: ResponseHeaders;
|
||||
/**
|
||||
* @internal
|
||||
* This is only used for integration tests that allow us to verify which config keys are exposed to the browser.
|
||||
*/
|
||||
includeExposedConfigKeys?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,156 +6,185 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ExposedToBrowserDescriptor } from './types';
|
||||
import type { PluginConfigDescriptor } from './types';
|
||||
import { createBrowserConfig } from './create_browser_config';
|
||||
import { schema, TypeOf } from '@kbn/config-schema';
|
||||
|
||||
describe('createBrowserConfig', () => {
|
||||
it('picks nothing by default', () => {
|
||||
const configSchema = schema.object({
|
||||
notExposed1: schema.string(),
|
||||
nested: schema.object({
|
||||
notExposed2: schema.boolean(),
|
||||
notExposed3: schema.maybe(schema.number()),
|
||||
}),
|
||||
});
|
||||
const config = {
|
||||
foo: 'bar',
|
||||
notExposed1: '1',
|
||||
nested: {
|
||||
str: 'string',
|
||||
num: 42,
|
||||
notExposed2: true,
|
||||
notExposed3: 3,
|
||||
},
|
||||
};
|
||||
const descriptor: ExposedToBrowserDescriptor<typeof config> = {};
|
||||
const descriptor: PluginConfigDescriptor<TypeOf<typeof configSchema>> = {
|
||||
schema: configSchema,
|
||||
};
|
||||
|
||||
const browserConfig = createBrowserConfig(config, descriptor);
|
||||
|
||||
expect(browserConfig).toEqual({});
|
||||
const result = createBrowserConfig(config, descriptor);
|
||||
expect(result).toEqual({ browserConfig: {}, exposedConfigKeys: {} });
|
||||
});
|
||||
|
||||
it('picks all the nested properties when using `true`', () => {
|
||||
const configSchema = schema.object({
|
||||
exposed1: schema.string(),
|
||||
nested: schema.object({
|
||||
exposed2: schema.boolean(),
|
||||
exposed3: schema.maybe(schema.number()),
|
||||
}),
|
||||
notExposed4: schema.string(),
|
||||
});
|
||||
const config = {
|
||||
foo: 'bar',
|
||||
exposed1: '1',
|
||||
nested: {
|
||||
str: 'string',
|
||||
num: 42,
|
||||
exposed2: true,
|
||||
exposed3: 3,
|
||||
},
|
||||
notExposed4: '4',
|
||||
};
|
||||
const descriptor: PluginConfigDescriptor<TypeOf<typeof configSchema>> = {
|
||||
schema: configSchema,
|
||||
exposeToBrowser: {
|
||||
exposed1: true,
|
||||
nested: true,
|
||||
},
|
||||
};
|
||||
|
||||
const descriptor: ExposedToBrowserDescriptor<typeof config> = {
|
||||
foo: true,
|
||||
nested: true,
|
||||
};
|
||||
|
||||
const browserConfig = createBrowserConfig(config, descriptor);
|
||||
|
||||
expect(browserConfig).toEqual({
|
||||
foo: 'bar',
|
||||
nested: {
|
||||
str: 'string',
|
||||
num: 42,
|
||||
const result = createBrowserConfig(config, descriptor);
|
||||
expect(result).toEqual({
|
||||
browserConfig: {
|
||||
exposed1: '1',
|
||||
nested: { exposed2: true, exposed3: 3 },
|
||||
// notExposed4 is not present
|
||||
},
|
||||
exposedConfigKeys: {
|
||||
exposed1: 'string',
|
||||
'nested.exposed2': 'boolean',
|
||||
'nested.exposed3': 'number',
|
||||
// notExposed4 is not present
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('picks specific nested properties when using a nested declaration', () => {
|
||||
it('picks specific nested properties, omitting those which are not specified', () => {
|
||||
const configSchema = schema.object({
|
||||
exposed1: schema.string(),
|
||||
nested: schema.object({
|
||||
exposed2: schema.boolean(),
|
||||
notExposed3: schema.maybe(schema.number()),
|
||||
}),
|
||||
notExposed4: schema.string(),
|
||||
});
|
||||
const config = {
|
||||
foo: 'bar',
|
||||
exposed1: '1',
|
||||
nested: {
|
||||
str: 'string',
|
||||
num: 42,
|
||||
exposed2: true,
|
||||
notExposed3: 3,
|
||||
},
|
||||
notExposed4: '4',
|
||||
};
|
||||
const descriptor: PluginConfigDescriptor<TypeOf<typeof configSchema>> = {
|
||||
schema: configSchema,
|
||||
exposeToBrowser: {
|
||||
exposed1: true,
|
||||
nested: { exposed2: true },
|
||||
},
|
||||
};
|
||||
|
||||
const descriptor: ExposedToBrowserDescriptor<typeof config> = {
|
||||
foo: true,
|
||||
nested: {
|
||||
str: true,
|
||||
num: false,
|
||||
const result = createBrowserConfig(config, descriptor);
|
||||
expect(result).toEqual({
|
||||
browserConfig: {
|
||||
exposed1: '1',
|
||||
nested: { exposed2: true },
|
||||
// notExposed3 and notExposed4 are not present
|
||||
},
|
||||
};
|
||||
|
||||
const browserConfig = createBrowserConfig(config, descriptor);
|
||||
|
||||
expect(browserConfig).toEqual({
|
||||
foo: 'bar',
|
||||
nested: {
|
||||
str: 'string',
|
||||
exposedConfigKeys: {
|
||||
exposed1: 'string',
|
||||
'nested.exposed2': 'boolean',
|
||||
// notExposed3 and notExposed4 are not present
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts deeply nested structures', () => {
|
||||
const config = {
|
||||
foo: 'bar',
|
||||
deeply: {
|
||||
str: 'string',
|
||||
nested: {
|
||||
hello: 'dolly',
|
||||
structure: {
|
||||
propA: 'propA',
|
||||
propB: 'propB',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const descriptor: ExposedToBrowserDescriptor<typeof config> = {
|
||||
foo: false,
|
||||
deeply: {
|
||||
str: false,
|
||||
nested: {
|
||||
hello: true,
|
||||
structure: {
|
||||
propA: true,
|
||||
propB: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const browserConfig = createBrowserConfig(config, descriptor);
|
||||
|
||||
expect(browserConfig).toEqual({
|
||||
deeply: {
|
||||
nested: {
|
||||
hello: 'dolly',
|
||||
structure: {
|
||||
propA: 'propA',
|
||||
},
|
||||
},
|
||||
},
|
||||
it('picks specific deeply nested properties, omitting those which are not specified', () => {
|
||||
const configSchema = schema.object({
|
||||
exposed1: schema.string(),
|
||||
deeply: schema.object({
|
||||
exposed2: schema.boolean(),
|
||||
nested: schema.object({
|
||||
exposed3: schema.maybe(schema.number()),
|
||||
structure: schema.object({
|
||||
exposed4: schema.string(),
|
||||
notExposed5: schema.string(),
|
||||
}),
|
||||
notExposed6: schema.string(),
|
||||
}),
|
||||
notExposed7: schema.string(),
|
||||
}),
|
||||
notExposed8: schema.string(),
|
||||
});
|
||||
});
|
||||
|
||||
it('only includes leaf properties that are `true` when in nested structures', () => {
|
||||
const config = {
|
||||
foo: 'bar',
|
||||
exposed1: '1',
|
||||
deeply: {
|
||||
str: 'string',
|
||||
exposed2: true,
|
||||
nested: {
|
||||
hello: 'dolly',
|
||||
exposed3: 3,
|
||||
structure: {
|
||||
propA: 'propA',
|
||||
propB: 'propB',
|
||||
exposed4: '4',
|
||||
notExposed5: '5',
|
||||
},
|
||||
notExposed6: '6',
|
||||
},
|
||||
notExposed7: '7',
|
||||
},
|
||||
notExposed8: '8',
|
||||
};
|
||||
const descriptor: PluginConfigDescriptor<TypeOf<typeof configSchema>> = {
|
||||
schema: configSchema,
|
||||
exposeToBrowser: {
|
||||
exposed1: true,
|
||||
deeply: {
|
||||
exposed2: true,
|
||||
nested: {
|
||||
exposed3: true,
|
||||
structure: {
|
||||
exposed4: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const descriptor: ExposedToBrowserDescriptor<typeof config> = {
|
||||
deeply: {
|
||||
nested: {
|
||||
hello: true,
|
||||
structure: {
|
||||
propA: true,
|
||||
const result = createBrowserConfig(config, descriptor);
|
||||
expect(result).toEqual({
|
||||
browserConfig: {
|
||||
exposed1: '1',
|
||||
deeply: {
|
||||
exposed2: true,
|
||||
nested: {
|
||||
exposed3: 3,
|
||||
structure: {
|
||||
exposed4: '4',
|
||||
},
|
||||
},
|
||||
},
|
||||
// notExposed5, notExposed6, notExposed7, and notExposed8 are not present
|
||||
},
|
||||
};
|
||||
|
||||
const browserConfig = createBrowserConfig(config, descriptor);
|
||||
|
||||
expect(browserConfig).toEqual({
|
||||
deeply: {
|
||||
nested: {
|
||||
hello: 'dolly',
|
||||
structure: {
|
||||
propA: 'propA',
|
||||
},
|
||||
},
|
||||
exposedConfigKeys: {
|
||||
exposed1: 'string',
|
||||
'deeply.exposed2': 'boolean',
|
||||
'deeply.nested.exposed3': 'number',
|
||||
'deeply.nested.structure.exposed4': 'string',
|
||||
// notExposed5, notExposed6, notExposed7, and notExposed8 are not present
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,19 +6,25 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ExposedToBrowserDescriptor } from './types';
|
||||
import { ExposedToBrowserDescriptor, PluginConfigDescriptor } from './types';
|
||||
|
||||
export const createBrowserConfig = <T = unknown>(
|
||||
config: T,
|
||||
descriptor: ExposedToBrowserDescriptor<T>
|
||||
): unknown => {
|
||||
return recursiveCreateConfig(config, descriptor);
|
||||
descriptor: PluginConfigDescriptor<T>
|
||||
) => {
|
||||
if (!descriptor.exposeToBrowser) {
|
||||
return { browserConfig: {}, exposedConfigKeys: {} };
|
||||
}
|
||||
return {
|
||||
browserConfig: recursiveCreateConfig(config, descriptor.exposeToBrowser),
|
||||
exposedConfigKeys: getExposedConfigKeys(descriptor),
|
||||
};
|
||||
};
|
||||
|
||||
const recursiveCreateConfig = <T = unknown>(
|
||||
config: T,
|
||||
descriptor: ExposedToBrowserDescriptor<T> = {}
|
||||
): unknown => {
|
||||
) => {
|
||||
return Object.entries(config || {}).reduce((browserConfig, [key, value]) => {
|
||||
const exposedConfig = descriptor[key as keyof ExposedToBrowserDescriptor<T>];
|
||||
if (exposedConfig && typeof exposedConfig === 'object') {
|
||||
|
@ -30,3 +36,39 @@ const recursiveCreateConfig = <T = unknown>(
|
|||
return browserConfig;
|
||||
}, {} as Record<string, unknown>);
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a plugin descriptor, this function returns an object that contains a flattened list of exposed config keys. This is used for a CI
|
||||
* check to ensure that consumers don't accidentally expose more config settings to the browser than intended.
|
||||
*/
|
||||
function getExposedConfigKeys<T = unknown>(descriptor: PluginConfigDescriptor<T>) {
|
||||
const schemaStructure = descriptor.schema.getSchemaStructure();
|
||||
const flattenedConfigSchema: Record<string, string> = {};
|
||||
for (const { path, type } of schemaStructure) {
|
||||
if (checkIsPathExposed(path, descriptor.exposeToBrowser!)) {
|
||||
flattenedConfigSchema[path.join('.')] = type;
|
||||
}
|
||||
}
|
||||
return flattenedConfigSchema;
|
||||
}
|
||||
|
||||
function checkIsPathExposed<T = unknown>(
|
||||
path: string[],
|
||||
descriptor: ExposedToBrowserDescriptor<T>
|
||||
) {
|
||||
let isExposed = false;
|
||||
for (const key of path) {
|
||||
// Traverse the path to see if it is exposed or not
|
||||
const exposedConfig = descriptor[key as keyof ExposedToBrowserDescriptor<T>];
|
||||
if (exposedConfig && typeof exposedConfig === 'object') {
|
||||
// @ts-expect-error Type 'undefined' is not assignable to type 'ExposedToBrowserDescriptor<T>'
|
||||
descriptor = exposedConfig;
|
||||
continue;
|
||||
}
|
||||
if (exposedConfig === true) {
|
||||
isExposed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return isExposed;
|
||||
}
|
||||
|
|
|
@ -1010,14 +1010,16 @@ describe('PluginsService', () => {
|
|||
|
||||
const prebootUIConfig$ = preboot.uiPlugins.browserConfigs.get('plugin-with-expose-preboot')!;
|
||||
await expect(prebootUIConfig$.pipe(take(1)).toPromise()).resolves.toEqual({
|
||||
sharedProp: 'sharedProp default value plugin-with-expose-preboot',
|
||||
browserConfig: { sharedProp: 'sharedProp default value plugin-with-expose-preboot' },
|
||||
exposedConfigKeys: { sharedProp: 'string' },
|
||||
});
|
||||
|
||||
const standardUIConfig$ = standard.uiPlugins.browserConfigs.get(
|
||||
'plugin-with-expose-standard'
|
||||
)!;
|
||||
await expect(standardUIConfig$.pipe(take(1)).toPromise()).resolves.toEqual({
|
||||
sharedProp: 'sharedProp default value plugin-with-expose-standard',
|
||||
browserConfig: { sharedProp: 'sharedProp default value plugin-with-expose-standard' },
|
||||
exposedConfigKeys: { sharedProp: 'string' },
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -231,9 +231,7 @@ export class PluginsService implements CoreService<PluginsServiceSetup, PluginsS
|
|||
pluginId,
|
||||
this.configService
|
||||
.atPath(plugin.configPath)
|
||||
.pipe(
|
||||
map((config: any) => createBrowserConfig(config, configDescriptor.exposeToBrowser!))
|
||||
),
|
||||
.pipe(map((config: any) => createBrowserConfig(config, configDescriptor))),
|
||||
];
|
||||
})
|
||||
);
|
||||
|
|
|
@ -79,7 +79,7 @@ export class RenderingService {
|
|||
{ http, uiPlugins, status }: RenderOptions,
|
||||
request: KibanaRequest,
|
||||
uiSettings: IUiSettingsClient,
|
||||
{ isAnonymousPage = false, vars }: IRenderOptions = {}
|
||||
{ isAnonymousPage = false, vars, includeExposedConfigKeys }: IRenderOptions = {}
|
||||
) {
|
||||
const env = {
|
||||
mode: this.coreContext.env.mode,
|
||||
|
@ -130,11 +130,15 @@ export class RenderingService {
|
|||
externalUrl: http.externalUrl,
|
||||
vars: vars ?? {},
|
||||
uiPlugins: await Promise.all(
|
||||
filteredPlugins.map(async ([id, plugin]) => ({
|
||||
id,
|
||||
plugin,
|
||||
config: await getUiConfig(uiPlugins, id),
|
||||
}))
|
||||
filteredPlugins.map(async ([id, plugin]) => {
|
||||
const { browserConfig, exposedConfigKeys } = await getUiConfig(uiPlugins, id);
|
||||
return {
|
||||
id,
|
||||
plugin,
|
||||
config: browserConfig,
|
||||
...(includeExposedConfigKeys && { exposedConfigKeys }),
|
||||
};
|
||||
})
|
||||
),
|
||||
legacyMetadata: {
|
||||
uiSettings: settings,
|
||||
|
@ -150,5 +154,8 @@ export class RenderingService {
|
|||
|
||||
const getUiConfig = async (uiPlugins: UiPlugins, pluginId: string) => {
|
||||
const browserConfig = uiPlugins.browserConfigs.get(pluginId);
|
||||
return ((await browserConfig?.pipe(take(1)).toPromise()) ?? {}) as Record<string, any>;
|
||||
return ((await browserConfig?.pipe(take(1)).toPromise()) ?? {
|
||||
browserConfig: {},
|
||||
exposedConfigKeys: {},
|
||||
}) as { browserConfig: Record<string, unknown>; exposedConfigKeys: Record<string, string> };
|
||||
};
|
||||
|
|
|
@ -85,6 +85,12 @@ export interface IRenderOptions {
|
|||
* @internal
|
||||
*/
|
||||
vars?: Record<string, any>;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* This is only used for integration tests that allow us to verify which config keys are exposed to the browser.
|
||||
*/
|
||||
includeExposedConfigKeys?: boolean;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
|
|
@ -1051,6 +1051,8 @@ export interface HttpResources {
|
|||
// @public
|
||||
export interface HttpResourcesRenderOptions {
|
||||
headers?: ResponseHeaders;
|
||||
// @internal
|
||||
includeExposedConfigKeys?: boolean;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
@ -1227,6 +1229,8 @@ export interface IntervalHistogram {
|
|||
|
||||
// @public (undocumented)
|
||||
export interface IRenderOptions {
|
||||
// @internal
|
||||
includeExposedConfigKeys?: boolean;
|
||||
isAnonymousPage?: boolean;
|
||||
// @internal @deprecated
|
||||
vars?: Record<string, any>;
|
||||
|
|
|
@ -22,7 +22,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
expect(resp.body).to.be.an('array');
|
||||
|
||||
expect(resp.body.length).to.be(13);
|
||||
expect(resp.body.length).to.be(34);
|
||||
|
||||
// Test for sample data card
|
||||
expect(resp.body.findIndex((c: { id: string }) => c.id === 'sample_data_all')).to.be.above(
|
||||
|
|
|
@ -71,13 +71,12 @@ export class TestUser extends FtrService {
|
|||
export async function createTestUserService(ctx: FtrProviderContext, role: Role, user: User) {
|
||||
const log = ctx.getService('log');
|
||||
const config = ctx.getService('config');
|
||||
const kibanaServer = ctx.getService('kibanaServer');
|
||||
|
||||
const enabledPlugins = config.get('security.disableTestUser')
|
||||
? []
|
||||
: await kibanaServer.plugins.getEnabledIds();
|
||||
|
||||
const enabled = enabledPlugins.includes('security') && !config.get('security.disableTestUser');
|
||||
const enabled =
|
||||
!config
|
||||
.get('esTestCluster.serverArgs')
|
||||
.some((arg: string) => arg === 'xpack.security.enabled=false') &&
|
||||
!config.get('security.disableTestUser');
|
||||
|
||||
if (enabled) {
|
||||
log.debug('===============creating roles and users===============');
|
||||
|
|
|
@ -46,10 +46,7 @@ export default async function ({ readConfigFile }) {
|
|||
'--xpack.maps.showMapVisualizationTypes=true',
|
||||
|
||||
// to be re-enabled once kibana/issues/102552 is completed
|
||||
'--xpack.security.enabled=false',
|
||||
'--monitoring.enabled=false',
|
||||
'--xpack.reporting.enabled=false',
|
||||
'--enterpriseSearch.enabled=false',
|
||||
],
|
||||
},
|
||||
|
||||
|
|
|
@ -31,9 +31,9 @@ export class RenderingPlugin implements Plugin {
|
|||
const { isAnonymousPage } = req.query;
|
||||
|
||||
if (isAnonymousPage) {
|
||||
return res.renderAnonymousCoreApp();
|
||||
return res.renderAnonymousCoreApp({ includeExposedConfigKeys: true });
|
||||
}
|
||||
return res.renderCoreApp();
|
||||
return res.renderCoreApp({ includeExposedConfigKeys: true });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
import '../../plugins/core_provider_plugin/types';
|
||||
|
@ -21,6 +22,9 @@ declare global {
|
|||
}
|
||||
}
|
||||
|
||||
const EXPOSED_CONFIG_SETTINGS_ERROR =
|
||||
'Actual config settings exposed to the browser do not match what is expected; this assertion fails if extra settings are present and/or expected settings are missing';
|
||||
|
||||
export default function ({ getService }: PluginFunctionalProviderContext) {
|
||||
const appsMenu = getService('appsMenu');
|
||||
const browser = getService('browser');
|
||||
|
@ -41,6 +45,10 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
|
|||
});
|
||||
};
|
||||
|
||||
const getInjectedMetadata = () =>
|
||||
browser.execute(() => {
|
||||
return JSON.parse(document.querySelector('kbn-injected-metadata')!.getAttribute('data')!);
|
||||
});
|
||||
const getUserSettings = () =>
|
||||
browser.execute(() => {
|
||||
return JSON.parse(document.querySelector('kbn-injected-metadata')!.getAttribute('data')!)
|
||||
|
@ -53,9 +61,201 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
|
|||
return window.__RENDERING_SESSION__;
|
||||
});
|
||||
|
||||
// Talked to @dover, he aggreed we can skip these tests that are unexpectedly flaky
|
||||
describe.skip('rendering service', () => {
|
||||
it('renders "core" application', async () => {
|
||||
describe('rendering service', () => {
|
||||
it('exposes plugin config settings to authenticated users', async () => {
|
||||
await navigateTo('/render/core');
|
||||
const injectedMetadata = await getInjectedMetadata();
|
||||
expect(injectedMetadata).to.not.be.empty();
|
||||
expect(injectedMetadata.uiPlugins).to.not.be.empty();
|
||||
|
||||
const actualExposedConfigKeys = [];
|
||||
for (const { plugin, exposedConfigKeys } of injectedMetadata.uiPlugins) {
|
||||
const configPath = Array.isArray(plugin.configPath)
|
||||
? plugin.configPath.join('.')
|
||||
: plugin.configPath;
|
||||
for (const [exposedConfigKey, type] of Object.entries(exposedConfigKeys)) {
|
||||
actualExposedConfigKeys.push(`${configPath}.${exposedConfigKey} (${type})`);
|
||||
}
|
||||
}
|
||||
const expectedExposedConfigKeys = [
|
||||
// NOTE: each exposed config key has its schema type at the end in "(parentheses)". The schema type comes from Joi; in particular,
|
||||
// "(any)" can mean a few other data types. This is only intended to be a hint to make it easier for future reviewers to understand
|
||||
// what types of config settings can be exposed to the browser.
|
||||
// When plugin owners make a change that exposes additional config values, the changes will be reflected in this test assertion.
|
||||
// Ensure that your change does not unintentionally expose any sensitive values!
|
||||
'console.ui.enabled (boolean)',
|
||||
'dashboard.allowByValueEmbeddables (boolean)',
|
||||
'data.autocomplete.querySuggestions.enabled (boolean)',
|
||||
'data.autocomplete.valueSuggestions.enabled (boolean)',
|
||||
'data.autocomplete.valueSuggestions.terminateAfter (duration)',
|
||||
'data.autocomplete.valueSuggestions.tiers (array)',
|
||||
'data.autocomplete.valueSuggestions.timeout (duration)',
|
||||
'data.search.aggs.shardDelay.enabled (boolean)',
|
||||
'enterpriseSearch.host (string)',
|
||||
'home.disableWelcomeScreen (boolean)',
|
||||
'kibana_legacy.defaultAppId (string)',
|
||||
'map.emsFileApiUrl (string)',
|
||||
'map.emsFontLibraryUrl (string)',
|
||||
'map.emsLandingPageUrl (string)',
|
||||
'map.emsTileApiUrl (string)',
|
||||
'map.emsTileLayerId.bright (string)',
|
||||
'map.emsTileLayerId.dark (string)',
|
||||
'map.emsTileLayerId.desaturated (string)',
|
||||
'map.emsUrl (any)',
|
||||
'map.manifestServiceUrl (string)',
|
||||
'map.proxyElasticMapsServiceInMaps (boolean)',
|
||||
'map.regionmap.includeElasticMapsService (boolean)',
|
||||
'map.regionmap.layers (array)',
|
||||
'map.includeElasticMapsService (boolean)',
|
||||
'map.tilemap.options.attribution (string)',
|
||||
'map.tilemap.options.bounds (array)',
|
||||
'map.tilemap.options.default (boolean)',
|
||||
'map.tilemap.options.errorTileUrl (string)',
|
||||
'map.tilemap.options.maxZoom (number)',
|
||||
'map.tilemap.options.minZoom (number)',
|
||||
'map.tilemap.options.reuseTiles (boolean)',
|
||||
'map.tilemap.options.subdomains (array)',
|
||||
'map.tilemap.options.tileSize (number)',
|
||||
'map.tilemap.options.tms (boolean)',
|
||||
'map.tilemap.url (string)',
|
||||
'monitoring.enabled (boolean)',
|
||||
'monitoring.kibana.collection.enabled (boolean)',
|
||||
'monitoring.kibana.collection.interval (number)',
|
||||
'monitoring.ui.ccs.enabled (boolean)',
|
||||
'monitoring.ui.container.apm.enabled (boolean)',
|
||||
'monitoring.ui.container.elasticsearch.enabled (boolean)',
|
||||
'monitoring.ui.container.logstash.enabled (boolean)',
|
||||
'monitoring.ui.enabled (boolean)',
|
||||
'monitoring.ui.min_interval_seconds (number)',
|
||||
'monitoring.ui.show_license_expiration (boolean)',
|
||||
'newsfeed.fetchInterval (duration)',
|
||||
'newsfeed.mainInterval (duration)',
|
||||
'newsfeed.service.pathTemplate (string)',
|
||||
'newsfeed.service.urlRoot (any)',
|
||||
'telemetry.allowChangingOptInStatus (boolean)',
|
||||
'telemetry.banner (boolean)',
|
||||
'telemetry.enabled (boolean)',
|
||||
'telemetry.optIn (any)',
|
||||
'telemetry.sendUsageFrom (alternatives)',
|
||||
'telemetry.sendUsageTo (any)',
|
||||
'usageCollection.uiCounters.debug (boolean)',
|
||||
'usageCollection.uiCounters.enabled (boolean)',
|
||||
'vis_type_vega.enableExternalUrls (boolean)',
|
||||
'xpack.apm.profilingEnabled (boolean)',
|
||||
'xpack.apm.serviceMapEnabled (boolean)',
|
||||
'xpack.apm.ui.enabled (boolean)',
|
||||
'xpack.apm.ui.maxTraceItems (number)',
|
||||
'xpack.apm.ui.transactionGroupBucketSize (number)',
|
||||
'xpack.cases.markdownPlugins.lens (boolean)',
|
||||
'xpack.ccr.ui.enabled (boolean)',
|
||||
'xpack.cloud.base_url (string)',
|
||||
'xpack.cloud.cname (string)',
|
||||
'xpack.cloud.deployment_url (string)',
|
||||
'xpack.cloud.full_story.enabled (boolean)',
|
||||
'xpack.cloud.full_story.org_id (any)',
|
||||
'xpack.cloud.id (string)',
|
||||
'xpack.cloud.organization_url (string)',
|
||||
'xpack.cloud.profile_url (string)',
|
||||
'xpack.data_enhanced.search.sessions.cleanupInterval (duration)',
|
||||
'xpack.data_enhanced.search.sessions.defaultExpiration (duration)',
|
||||
'xpack.data_enhanced.search.sessions.enabled (boolean)',
|
||||
'xpack.data_enhanced.search.sessions.expireInterval (duration)',
|
||||
'xpack.data_enhanced.search.sessions.management.expiresSoonWarning (duration)',
|
||||
'xpack.data_enhanced.search.sessions.management.maxSessions (number)',
|
||||
'xpack.data_enhanced.search.sessions.management.refreshInterval (duration)',
|
||||
'xpack.data_enhanced.search.sessions.management.refreshTimeout (duration)',
|
||||
'xpack.data_enhanced.search.sessions.maxUpdateRetries (number)',
|
||||
'xpack.data_enhanced.search.sessions.monitoringTaskTimeout (duration)',
|
||||
'xpack.data_enhanced.search.sessions.notTouchedInProgressTimeout (duration)',
|
||||
'xpack.data_enhanced.search.sessions.notTouchedTimeout (duration)',
|
||||
'xpack.data_enhanced.search.sessions.pageSize (number)',
|
||||
'xpack.data_enhanced.search.sessions.trackingInterval (duration)',
|
||||
'xpack.discoverEnhanced.actions.exploreDataInChart.enabled (boolean)',
|
||||
'xpack.discoverEnhanced.actions.exploreDataInContextMenu.enabled (boolean)',
|
||||
'xpack.fleet.agents.enabled (boolean)',
|
||||
'xpack.global_search.search_timeout (duration)',
|
||||
'xpack.graph.canEditDrillDownUrls (boolean)',
|
||||
'xpack.graph.savePolicy (alternatives)',
|
||||
'xpack.ilm.ui.enabled (boolean)',
|
||||
'xpack.index_management.ui.enabled (boolean)',
|
||||
'xpack.license_management.ui.enabled (boolean)',
|
||||
'xpack.maps.enabled (boolean)',
|
||||
'xpack.maps.preserveDrawingBuffer (boolean)',
|
||||
'xpack.maps.showMapsInspectorAdapter (boolean)',
|
||||
'xpack.maps.showMapVisualizationTypes (boolean)',
|
||||
'xpack.observability.unsafe.alertingExperience.enabled (boolean)',
|
||||
'xpack.observability.unsafe.cases.enabled (boolean)',
|
||||
'xpack.osquery.actionEnabled (boolean)',
|
||||
'xpack.osquery.enabled (boolean)',
|
||||
'xpack.osquery.packs (boolean)',
|
||||
'xpack.osquery.savedQueries (boolean)',
|
||||
'xpack.remote_clusters.ui.enabled (boolean)',
|
||||
/**
|
||||
* NOTE: The Reporting plugin is currently disabled in functional tests (see test/functional/config.js).
|
||||
* It will be re-enabled once #102552 is completed.
|
||||
*/
|
||||
// 'xpack.reporting.roles.allow (array)',
|
||||
// 'xpack.reporting.roles.enabled (boolean)',
|
||||
// 'xpack.reporting.poll.jobCompletionNotifier.interval (number)',
|
||||
// 'xpack.reporting.poll.jobCompletionNotifier.intervalErrorMultiplier (number)',
|
||||
// 'xpack.reporting.poll.jobsRefresh.interval (number)',
|
||||
// 'xpack.reporting.poll.jobsRefresh.intervalErrorMultiplier (number)',
|
||||
'xpack.rollup.ui.enabled (boolean)',
|
||||
'xpack.saved_object_tagging.cache_refresh_interval (duration)',
|
||||
'xpack.security.loginAssistanceMessage (string)',
|
||||
'xpack.security.sameSiteCookies (alternatives)',
|
||||
'xpack.security.showInsecureClusterWarning (boolean)',
|
||||
'xpack.securitySolution.enableExperimental (array)',
|
||||
'xpack.snapshot_restore.slm_ui.enabled (boolean)',
|
||||
'xpack.snapshot_restore.ui.enabled (boolean)',
|
||||
'xpack.timelines.enabled (boolean)',
|
||||
'xpack.trigger_actions_ui.enableGeoTrackingThresholdAlert (boolean)',
|
||||
'xpack.upgrade_assistant.readonly (boolean)',
|
||||
'xpack.upgrade_assistant.ui.enabled (boolean)',
|
||||
];
|
||||
// We don't assert that actualExposedConfigKeys and expectedExposedConfigKeys are equal, because test failure messages with large
|
||||
// arrays are hard to grok. Instead, we take the difference between the two arrays and assert them separately, that way it's
|
||||
// abundantly clear when the test fails that (A) Kibana is exposing a new key, or (B) Kibana is no longer exposing a key.
|
||||
const extra = _.difference(actualExposedConfigKeys, expectedExposedConfigKeys).sort();
|
||||
const missing = _.difference(expectedExposedConfigKeys, actualExposedConfigKeys).sort();
|
||||
expect({ extra, missing }).to.eql({ extra: [], missing: [] }, EXPOSED_CONFIG_SETTINGS_ERROR);
|
||||
});
|
||||
|
||||
it('exposes plugin config settings to unauthenticated users', async () => {
|
||||
await navigateTo('/render/core?isAnonymousPage=true');
|
||||
const injectedMetadata = await getInjectedMetadata();
|
||||
expect(injectedMetadata).to.not.be.empty();
|
||||
expect(injectedMetadata.uiPlugins).to.not.be.empty();
|
||||
|
||||
const actualExposedConfigKeys = [];
|
||||
for (const { plugin, exposedConfigKeys } of injectedMetadata.uiPlugins) {
|
||||
const configPath = Array.isArray(plugin.configPath)
|
||||
? plugin.configPath.join('.')
|
||||
: plugin.configPath;
|
||||
for (const [exposedConfigKey, type] of Object.entries(exposedConfigKeys)) {
|
||||
actualExposedConfigKeys.push(`${configPath}.${exposedConfigKey} (${type})`);
|
||||
}
|
||||
}
|
||||
const expectedExposedConfigKeys = [
|
||||
// NOTE: each exposed config key has its schema type at the end in "(parentheses)". The schema type comes from Joi; in particular,
|
||||
// "(any)" can mean a few other data types. This is only intended to be a hint to make it easier for future reviewers to understand
|
||||
// what types of config settings can be exposed to the browser.
|
||||
// When plugin owners make a change that exposes additional config values, the changes will be reflected in this test assertion.
|
||||
// Ensure that your change does not unintentionally expose any sensitive values!
|
||||
'xpack.security.loginAssistanceMessage (string)',
|
||||
'xpack.security.sameSiteCookies (alternatives)',
|
||||
'xpack.security.showInsecureClusterWarning (boolean)',
|
||||
];
|
||||
// We don't assert that actualExposedConfigKeys and expectedExposedConfigKeys are equal, because test failure messages with large
|
||||
// arrays are hard to grok. Instead, we take the difference between the two arrays and assert them separately, that way it's
|
||||
// abundantly clear when the test fails that (A) Kibana is exposing a new key, or (B) Kibana is no longer exposing a key.
|
||||
const extra = _.difference(actualExposedConfigKeys, expectedExposedConfigKeys).sort();
|
||||
const missing = _.difference(expectedExposedConfigKeys, actualExposedConfigKeys).sort();
|
||||
expect({ extra, missing }).to.eql({ extra: [], missing: [] }, EXPOSED_CONFIG_SETTINGS_ERROR);
|
||||
});
|
||||
|
||||
// FLAKY
|
||||
it.skip('renders "core" application', async () => {
|
||||
await navigateTo('/render/core');
|
||||
|
||||
const [loadingMessage, userSettings] = await Promise.all([
|
||||
|
@ -70,7 +270,8 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
|
|||
expect(await exists('renderingHeader')).to.be(true);
|
||||
});
|
||||
|
||||
it('renders "core" application without user settings', async () => {
|
||||
// FLAKY
|
||||
it.skip('renders "core" application without user settings', async () => {
|
||||
await navigateTo('/render/core?isAnonymousPage=true');
|
||||
|
||||
const [loadingMessage, userSettings] = await Promise.all([
|
||||
|
@ -85,7 +286,8 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
|
|||
expect(await exists('renderingHeader')).to.be(true);
|
||||
});
|
||||
|
||||
it('navigates between standard application and one with custom appRoute', async () => {
|
||||
// FLAKY
|
||||
it.skip('navigates between standard application and one with custom appRoute', async () => {
|
||||
await navigateTo('/');
|
||||
await find.waitForElementStale(await findLoadingMessage());
|
||||
|
||||
|
@ -108,7 +310,8 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
|
|||
]);
|
||||
});
|
||||
|
||||
it('navigates between applications with custom appRoutes', async () => {
|
||||
// FLAKY
|
||||
it.skip('navigates between applications with custom appRoutes', async () => {
|
||||
await navigateTo('/');
|
||||
await find.waitForElementStale(await findLoadingMessage());
|
||||
|
||||
|
|
|
@ -242,7 +242,9 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
|||
},
|
||||
},
|
||||
})}`,
|
||||
...disabledPlugins.map((key) => `--xpack.${key}.enabled=false`),
|
||||
...disabledPlugins
|
||||
.filter((k) => k !== 'security')
|
||||
.map((key) => `--xpack.${key}.enabled=false`),
|
||||
...plugins.map(
|
||||
(pluginDir) =>
|
||||
`--plugin-path=${path.resolve(__dirname, 'fixtures', 'plugins', pluginDir)}`
|
||||
|
|
|
@ -121,7 +121,9 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
|||
`--xpack.actions.allowedHosts=${JSON.stringify(['localhost', 'some.non.existent.com'])}`,
|
||||
`--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`,
|
||||
'--xpack.eventLog.logEntries=true',
|
||||
...disabledPlugins.map((key) => `--xpack.${key}.enabled=false`),
|
||||
...disabledPlugins
|
||||
.filter((k) => k !== 'security')
|
||||
.map((key) => `--xpack.${key}.enabled=false`),
|
||||
// Actions simulators plugin. Needed for testing push to external services.
|
||||
...alertingPlugins.map(
|
||||
(pluginDir) =>
|
||||
|
|
|
@ -51,7 +51,9 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
|||
...xPackApiIntegrationTestsConfig.get('kbnTestServer'),
|
||||
serverArgs: [
|
||||
...xPackApiIntegrationTestsConfig.get('kbnTestServer.serverArgs'),
|
||||
...disabledPlugins.map((key) => `--xpack.${key}.enabled=false`),
|
||||
...disabledPlugins
|
||||
.filter((k) => k !== 'security')
|
||||
.map((key) => `--xpack.${key}.enabled=false`),
|
||||
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`,
|
||||
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions')}`,
|
||||
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'task_manager')}`,
|
||||
|
|
|
@ -24,7 +24,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
},
|
||||
kbnTestServer: {
|
||||
...apiConfig.get('kbnTestServer'),
|
||||
serverArgs: [...apiConfig.get('kbnTestServer.serverArgs'), `--xpack.security.enabled=false`],
|
||||
serverArgs: [...apiConfig.get('kbnTestServer.serverArgs')],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,10 +17,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
testFiles: [resolve(__dirname, './reporting_without_security')],
|
||||
kbnTestServer: {
|
||||
...reportingConfig.get('kbnTestServer'),
|
||||
serverArgs: [
|
||||
...reportingConfig.get('kbnTestServer.serverArgs'),
|
||||
`--xpack.security.enabled=false`,
|
||||
],
|
||||
serverArgs: [...reportingConfig.get('kbnTestServer.serverArgs')],
|
||||
},
|
||||
esTestCluster: {
|
||||
...reportingConfig.get('esTestCluster'),
|
||||
|
|
|
@ -79,7 +79,9 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
|||
`--xpack.actions.allowedHosts=${JSON.stringify(['localhost', 'some.non.existent.com'])}`,
|
||||
`--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`,
|
||||
'--xpack.eventLog.logEntries=true',
|
||||
...disabledPlugins.map((key) => `--xpack.${key}.enabled=false`),
|
||||
...disabledPlugins
|
||||
.filter((k) => k !== 'security')
|
||||
.map((key) => `--xpack.${key}.enabled=false`),
|
||||
// TO DO: Remove feature flags once we're good to go
|
||||
'--xpack.securitySolution.enableExperimental=["ruleRegistryEnabled"]',
|
||||
'--xpack.ruleRegistry.write.enabled=true',
|
||||
|
|
|
@ -54,7 +54,9 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
|||
...config.xpack.api.get('kbnTestServer.serverArgs'),
|
||||
'--server.xsrf.disableProtection=true',
|
||||
`--plugin-path=${path.join(__dirname, 'fixtures', 'saved_object_test_plugin')}`,
|
||||
...disabledPlugins.map((key) => `--xpack.${key}.enabled=false`),
|
||||
...disabledPlugins
|
||||
.filter((k) => k !== 'security')
|
||||
.map((key) => `--xpack.${key}.enabled=false`),
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -61,7 +61,9 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
|||
'--status.allowAnonymous=false',
|
||||
'--server.xsrf.disableProtection=true',
|
||||
`--plugin-path=${path.join(__dirname, 'fixtures', 'spaces_test_plugin')}`,
|
||||
...disabledPlugins.map((key) => `--xpack.${key}.enabled=false`),
|
||||
...disabledPlugins
|
||||
.filter((k) => k !== 'security')
|
||||
.map((key) => `--xpack.${key}.enabled=false`),
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -81,7 +81,9 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
|||
`--xpack.actions.allowedHosts=${JSON.stringify(['localhost', 'some.non.existent.com'])}`,
|
||||
`--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`,
|
||||
'--xpack.eventLog.logEntries=true',
|
||||
...disabledPlugins.map((key) => `--xpack.${key}.enabled=false`),
|
||||
...disabledPlugins
|
||||
.filter((k) => k !== 'security')
|
||||
.map((key) => `--xpack.${key}.enabled=false`),
|
||||
// TO DO: Remove feature flags once we're good to go
|
||||
'--xpack.securitySolution.enableExperimental=["ruleRegistryEnabled"]',
|
||||
'--xpack.ruleRegistry.write.enabled=true',
|
||||
|
|
|
@ -42,7 +42,9 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
|||
...xPackFunctionalTestsConfig.get('kbnTestServer'),
|
||||
serverArgs: [
|
||||
...xPackFunctionalTestsConfig.get('kbnTestServer.serverArgs'),
|
||||
...disabledPlugins.map((key) => `--xpack.${key}.enabled=false`),
|
||||
...disabledPlugins
|
||||
.filter((k) => k !== 'security')
|
||||
.map((key) => `--xpack.${key}.enabled=false`),
|
||||
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'foo_plugin')}`,
|
||||
],
|
||||
},
|
||||
|
|
|
@ -55,7 +55,7 @@ export default function catalogueTests({ getService }: FtrProviderContext) {
|
|||
// only foo is disabled
|
||||
const expected = mapValues(
|
||||
uiCapabilities.value!.catalogue,
|
||||
(value, catalogueId) => catalogueId !== 'foo'
|
||||
(enabled, catalogueId) => catalogueId !== 'foo'
|
||||
);
|
||||
expect(uiCapabilities.value!.catalogue).to.eql(expected);
|
||||
break;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue