fix: kbn-config-schema tests for conditional config schemas (#190259)

This commit is contained in:
Nick Partridge 2024-08-13 11:54:56 -07:00 committed by GitHub
parent f3dc8a6d5d
commit 2f9dca4b02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 361 additions and 285 deletions

View file

@ -69,7 +69,7 @@ describe('createBrowserConfig', () => {
exposedConfigKeys: {
exposed1: 'string',
'nested.exposed2': 'boolean',
'nested.exposed3': 'number',
'nested.exposed3': 'number?',
// notExposed4 is not present
},
});
@ -182,7 +182,7 @@ describe('createBrowserConfig', () => {
exposedConfigKeys: {
exposed1: 'string',
'deeply.exposed2': 'boolean',
'deeply.nested.exposed3': 'number',
'deeply.nested.exposed3': 'number?',
'deeply.nested.structure.exposed4': 'string',
// notExposed5, notExposed6, notExposed7, and notExposed8 are not present
},

View file

@ -1046,7 +1046,7 @@ describe('PluginsService', () => {
const prebootUIConfig$ = preboot.uiPlugins.browserConfigs.get('plugin-with-expose-preboot')!;
await expect(prebootUIConfig$.pipe(take(1)).toPromise()).resolves.toEqual({
browserConfig: { sharedProp: 'sharedProp default value plugin-with-expose-preboot' },
exposedConfigKeys: { sharedProp: 'string' },
exposedConfigKeys: { sharedProp: 'string?' },
});
const standardUIConfig$ = standard.uiPlugins.browserConfigs.get(
@ -1054,7 +1054,7 @@ describe('PluginsService', () => {
)!;
await expect(standardUIConfig$.pipe(take(1)).toPromise()).resolves.toEqual({
browserConfig: { sharedProp: 'sharedProp default value plugin-with-expose-standard' },
exposedConfigKeys: { sharedProp: 'string' },
exposedConfigKeys: { sharedProp: 'string?' },
});
});

View file

@ -8,7 +8,7 @@
import { get } from 'lodash';
import { expectType } from 'tsd';
import { schema } from '../..';
import { offeringBasedSchema, schema } from '../..';
import { TypeOf } from './object_type';
test('returns value by default', () => {
@ -682,6 +682,10 @@ test('returns schema structure', () => {
boolean: schema.boolean(),
buffer: schema.buffer(),
byteSize: schema.byteSize(),
svlConditional: offeringBasedSchema({
serverless: schema.literal('serverless'),
traditional: schema.literal('stateful'),
}),
conditional: schema.conditional(
schema.contextRef('context_value_1'),
schema.contextRef('context_value_2'),
@ -699,8 +703,9 @@ test('returns schema structure', () => {
record: schema.recordOf(schema.string(), schema.string()),
stream: schema.stream(),
string: schema.string(),
union: schema.oneOf([schema.string()]),
union: schema.oneOf([schema.string(), schema.number(), schema.boolean()]),
uri: schema.uri(),
null: schema.literal(null),
});
const type = objSchema.extends({
nested: objSchema,
@ -711,39 +716,43 @@ test('returns schema structure', () => {
{ path: ['boolean'], type: 'boolean' },
{ path: ['buffer'], type: 'binary' },
{ path: ['byteSize'], type: 'bytes' },
{ path: ['conditional'], type: 'any' },
{ path: ['svlConditional'], type: 'serverless|stateful' },
{ path: ['conditional'], type: 'string' },
{ path: ['duration'], type: 'duration' },
{ path: ['ip'], type: 'string' },
{ path: ['literal'], type: 'any' },
{ path: ['literal'], type: 'foo' },
{ path: ['map'], type: 'map' },
{ path: ['maybe'], type: 'string' },
{ path: ['never'], type: 'any' },
{ path: ['nullable'], type: 'alternatives' },
{ path: ['maybe'], type: 'string?' },
{ path: ['never'], type: 'never' },
{ path: ['nullable'], type: 'string?|null' },
{ path: ['number'], type: 'number' },
{ path: ['record'], type: 'record' },
{ path: ['stream'], type: 'stream' },
{ path: ['string'], type: 'string' },
{ path: ['union'], type: 'alternatives' },
{ path: ['union'], type: 'string|number|boolean' },
{ path: ['uri'], type: 'string' },
{ path: ['null'], type: 'null' },
{ 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', 'svlConditional'], type: 'serverless|stateful' },
{ path: ['nested', 'conditional'], type: 'string' },
{ path: ['nested', 'duration'], type: 'duration' },
{ path: ['nested', 'ip'], type: 'string' },
{ path: ['nested', 'literal'], type: 'any' },
{ path: ['nested', 'literal'], type: 'foo' },
{ path: ['nested', 'map'], type: 'map' },
{ path: ['nested', 'maybe'], type: 'string' },
{ path: ['nested', 'never'], type: 'any' },
{ path: ['nested', 'nullable'], type: 'alternatives' },
{ path: ['nested', 'maybe'], type: 'string?' },
{ path: ['nested', 'never'], type: 'never' },
{ path: ['nested', 'nullable'], type: 'string?|null' },
{ 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', 'union'], type: 'string|number|boolean' },
{ path: ['nested', 'uri'], type: 'string' },
{ path: ['nested', 'null'], type: 'null' },
]);
});

View file

@ -6,7 +6,15 @@
* Side Public License, v 1.
*/
import type { AnySchema, CustomValidator, ErrorReport } from 'joi';
import {
isSchema,
type CustomValidator,
type ErrorReport,
type Schema,
type SchemaLike,
type WhenOptions,
CustomHelpers,
} from 'joi';
import { META_FIELD_X_OAS_DEPRECATED } from '../oas_meta_fields';
import { SchemaTypeError, ValidationError } from '../errors';
import { Reference } from '../references';
@ -91,9 +99,9 @@ export abstract class Type<V> {
* Internal "schema" backed by Joi.
* @type {Schema}
*/
protected readonly internalSchema: AnySchema;
protected readonly internalSchema: Schema;
protected constructor(schema: AnySchema, options: TypeOptions<V> = {}) {
protected constructor(schema: Schema, options: TypeOptions<V> = {}) {
if (options.defaultValue !== undefined) {
schema = schema.optional();
@ -214,7 +222,7 @@ export abstract class Type<V> {
}
}
function recursiveGetSchemaStructure(internalSchema: AnySchema, path: string[] = []) {
function recursiveGetSchemaStructure(internalSchema: Schema, 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.
@ -222,8 +230,69 @@ function recursiveGetSchemaStructure(internalSchema: AnySchema, path: string[] =
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' });
let type: string;
try {
type = prettyPrintType(internalSchema, path);
} catch (error) {
// failed to find special type, might need to update for new joi versions or type usages
type = internalSchema.type || 'unknown';
}
array.push({
path,
type,
});
}
return array;
}
/**
* Returns a more accurate type from complex schema definitions.
*
* For example, conditional values resolve to type `any` when the nested value is only ever a `string`.
*
* @param internalSchema
* @param path of current schema
* @returns schema type
*/
function prettyPrintType(schema?: SchemaLike, path: string[] = []): string {
// takes array of possible values and de-dups and joins
return [...new Set([prettyPrintTypeParts(schema, false, path)].flat())].filter(Boolean).join('|');
}
/**
* Recursively collects all possible nested schema types.
*/
function prettyPrintTypeParts(
schema?: SchemaLike,
optional = false,
path: string[] = []
): string | string[] {
if (!isSchema(schema)) {
if (schema === null) return 'null';
return `${schema ?? 'unknown'}${optional ? '?' : ''}`;
}
const isOptionalType = optional || schema._flags?.presence === 'optional';
// For explicit custom schema.never
if (schema._flags?.presence === 'forbidden') return 'never';
// For offeringBasedSchema, schema.when, schema.conditional
if (schema.$_terms?.whens?.length > 0)
return (schema.$_terms.whens as WhenOptions[]).flatMap((when) =>
[when?.then, when?.otherwise].flatMap((s) => prettyPrintTypeParts(s, isOptionalType, path))
);
// schema.oneOf, schema.allOf, etc.
if (schema.$_terms?.matches?.length > 0)
return (schema.$_terms.matches as CustomHelpers[]).flatMap((s) =>
prettyPrintTypeParts(s.schema, isOptionalType, path)
);
// schema.literal
if (schema._flags?.only && (schema as any)._valids?._values?.size > 0)
return [...(schema as any)._valids._values.keys()].flatMap((v) =>
prettyPrintTypeParts(v, isOptionalType, path)
);
return `${schema?.type || 'unknown'}${isOptionalType ? '?' : ''}`;
}

View file

@ -100,211 +100,209 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
// 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.autocompleteDefinitions.endpointsAvailability (alternatives)',
'console.dev.enableMonaco (boolean)',
'console.ui.enabled (boolean)',
'console.ui.embeddedEnabled (boolean)',
'dashboard.allowByValueEmbeddables (boolean)',
'unifiedSearch.autocomplete.querySuggestions.enabled (boolean)',
'unifiedSearch.autocomplete.valueSuggestions.enabled (boolean)',
'unifiedSearch.autocomplete.valueSuggestions.terminateAfter (duration)',
'unifiedSearch.autocomplete.valueSuggestions.tiers (array)',
'unifiedSearch.autocomplete.valueSuggestions.timeout (duration)',
'data.search.aggs.shardDelay.enabled (boolean)',
'data.search.asyncSearch.batchedReduceSize (number)',
'data.search.asyncSearch.keepAlive (duration)',
'data.search.asyncSearch.waitForCompletion (duration)',
'data.search.asyncSearch.pollInterval (number)',
'data.search.sessions.defaultExpiration (duration)',
'data.search.sessions.enabled (boolean)',
'data.search.sessions.management.expiresSoonWarning (duration)',
'data.search.sessions.management.maxSessions (number)',
'data.search.sessions.management.refreshInterval (duration)',
'data.search.sessions.management.refreshTimeout (duration)',
'data.search.sessions.maxUpdateRetries (number)',
'data.search.sessions.notTouchedTimeout (duration)',
'data_views.scriptedFieldsEnabled (any)', // It's a boolean (any because schema.conditional)
'console.autocompleteDefinitions.endpointsAvailability (stack?|serverless?)',
'console.dev.enableMonaco (boolean?)',
'console.ui.enabled (boolean?)',
'console.ui.embeddedEnabled (boolean?)',
'dashboard.allowByValueEmbeddables (boolean?)',
'unifiedSearch.autocomplete.querySuggestions.enabled (boolean?)',
'unifiedSearch.autocomplete.valueSuggestions.enabled (boolean?)',
'unifiedSearch.autocomplete.valueSuggestions.terminateAfter (duration?)',
'unifiedSearch.autocomplete.valueSuggestions.tiers (array?)',
'unifiedSearch.autocomplete.valueSuggestions.timeout (duration?)',
'data.search.aggs.shardDelay.enabled (boolean?)',
'data.search.asyncSearch.batchedReduceSize (number?)',
'data.search.asyncSearch.keepAlive (duration?)',
'data.search.asyncSearch.waitForCompletion (duration?)',
'data.search.asyncSearch.pollInterval (number?)',
'data.search.sessions.defaultExpiration (duration?)',
'data.search.sessions.enabled (boolean?)',
'data.search.sessions.management.expiresSoonWarning (duration?)',
'data.search.sessions.management.maxSessions (number?)',
'data.search.sessions.management.refreshInterval (duration?)',
'data.search.sessions.management.refreshTimeout (duration?)',
'data.search.sessions.maxUpdateRetries (number?)',
'data.search.sessions.notTouchedTimeout (duration?)',
'data_views.scriptedFieldsEnabled (boolean?|never)',
'data_visualizer.resultLinks.fileBeat.enabled (boolean)',
'dev_tools.deeplinks.navLinkStatus (string)',
'discover.experimental.enabledProfiles (array)',
'enterpriseSearch.canDeployEntSearch (boolean)',
'enterpriseSearch.host (string)',
'enterpriseSearch.ui.enabled (boolean)',
'home.disableWelcomeScreen (boolean)',
'management.deeplinks.navLinkStatus (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 (string)',
'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.kibana.collection.enabled (boolean)',
'monitoring.kibana.collection.interval (number)',
'monitoring.ui.ccs.enabled (boolean)',
'monitoring.ui.kibana.reporting.stale_status_threshold_seconds (number)',
'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 (string)',
'no_data_page.analyticsNoDataPageFlavor (any)', // It's a string (any because schema.conditional)
'telemetry.allowChangingOptInStatus (boolean)',
'telemetry.appendServerlessChannelsSuffix (any)', // It's a boolean (any because schema.conditional)
'telemetry.banner (boolean)',
'telemetry.labels.branch (string)',
'telemetry.labels.ciBuildId (string)',
'telemetry.labels.ciBuildJobId (string)',
'telemetry.labels.ciBuildNumber (number)',
'telemetry.labels.environment (string)',
'telemetry.labels.ftrConfig (string)',
'telemetry.labels.gitRev (string)',
'telemetry.labels.isPr (boolean)',
'telemetry.labels.journeyName (string)',
'telemetry.labels.prId (number)',
'telemetry.labels.testBuildId (string)',
'telemetry.labels.testJobId (string)',
'telemetry.labels.ciBuildName (string)',
'telemetry.labels.performancePhase (string)',
'telemetry.labels.serverless (any)', // It's the project type (string), claims any because schema.conditional. Can only be set on Serverless.
'telemetry.hidePrivacyStatement (boolean)',
'telemetry.optIn (boolean)',
'telemetry.sendUsageFrom (alternatives)',
'telemetry.sendUsageTo (any)',
'usageCollection.uiCounters.debug (boolean)',
'usageCollection.uiCounters.enabled (boolean)',
// readOnly is boolean flag
'input_control_vis.readOnly (any)',
'vis_type_gauge.readOnly (any)',
'vis_type_heatmap.readOnly (any)',
'vis_type_metric.readOnly (any)',
'vis_type_pie.readOnly (any)',
'vis_type_table.readOnly (any)',
'vis_type_tagcloud.readOnly (any)',
'vis_type_timelion.readOnly (any)',
'vis_type_timeseries.readOnly (any)',
'vis_type_vislib.readOnly (any)',
'vis_type_xy.readOnly (any)',
'vis_type_vega.enableExternalUrls (boolean)',
'dev_tools.deeplinks.navLinkStatus (string?)',
'discover.experimental.enabledProfiles (array?)',
'enterpriseSearch.canDeployEntSearch (boolean?)',
'enterpriseSearch.host (string?)',
'enterpriseSearch.ui.enabled (boolean?)',
'home.disableWelcomeScreen (boolean?)',
'management.deeplinks.navLinkStatus (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 (string?)',
'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.kibana.collection.enabled (boolean?)',
'monitoring.kibana.collection.interval (number?)',
'monitoring.ui.ccs.enabled (boolean?)',
'monitoring.ui.kibana.reporting.stale_status_threshold_seconds (number?)',
'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 (string?)',
'no_data_page.analyticsNoDataPageFlavor (kibana?|serverless_search?|serverless_observability?|never)',
'telemetry.allowChangingOptInStatus (boolean?)',
'telemetry.appendServerlessChannelsSuffix (true?|false?)',
'telemetry.banner (boolean?)',
'telemetry.labels.branch (string?)',
'telemetry.labels.ciBuildId (string?)',
'telemetry.labels.ciBuildJobId (string?)',
'telemetry.labels.ciBuildNumber (number?)',
'telemetry.labels.environment (string?)',
'telemetry.labels.ftrConfig (string?)',
'telemetry.labels.gitRev (string?)',
'telemetry.labels.isPr (boolean?)',
'telemetry.labels.journeyName (string?)',
'telemetry.labels.prId (number?)',
'telemetry.labels.testBuildId (string?)',
'telemetry.labels.testJobId (string?)',
'telemetry.labels.ciBuildName (string?)',
'telemetry.labels.performancePhase (string?)',
'telemetry.labels.serverless (string?|never)', // Can only be set on Serverless.
'telemetry.hidePrivacyStatement (boolean?)',
'telemetry.optIn (boolean?)',
'telemetry.sendUsageFrom (server?|browser?)',
'telemetry.sendUsageTo (prod?|staging?)',
'usageCollection.uiCounters.debug (boolean?)',
'usageCollection.uiCounters.enabled (boolean?)',
'input_control_vis.readOnly (boolean?|never)',
'vis_type_gauge.readOnly (boolean?|never)',
'vis_type_heatmap.readOnly (boolean?|never)',
'vis_type_metric.readOnly (boolean?|never)',
'vis_type_pie.readOnly (boolean?|never)',
'vis_type_table.readOnly (boolean?|never)',
'vis_type_tagcloud.readOnly (boolean?|never)',
'vis_type_timelion.readOnly (boolean?|never)',
'vis_type_timeseries.readOnly (boolean?|never)',
'vis_type_vislib.readOnly (boolean?|never)',
'vis_type_xy.readOnly (boolean?|never)',
'vis_type_vega.enableExternalUrls (boolean?)',
'xpack.actions.email.domain_allowlist (array)',
'xpack.apm.serviceMapEnabled (boolean)',
'xpack.apm.ui.enabled (boolean)',
'xpack.apm.ui.maxTraceItems (number)',
'xpack.apm.managedServiceUrl (any)',
'xpack.apm.serverlessOnboarding (any)',
'xpack.apm.latestAgentVersionsUrl (string)',
'xpack.apm.featureFlags.agentConfigurationAvailable (any)',
'xpack.apm.featureFlags.configurableIndicesAvailable (any)',
'xpack.apm.featureFlags.infrastructureTabAvailable (any)',
'xpack.apm.featureFlags.infraUiAvailable (any)',
'xpack.apm.featureFlags.migrationToFleetAvailable (any)',
'xpack.apm.featureFlags.sourcemapApiAvailable (any)',
'xpack.apm.featureFlags.storageExplorerAvailable (any)',
'xpack.apm.featureFlags.profilingIntegrationAvailable (boolean)',
'xpack.apm.serverless.enabled (any)', // It's a boolean (any because schema.conditional)
'xpack.observability_onboarding.serverless.enabled (any)', // It's a boolean (any because schema.conditional)
'xpack.cases.files.allowedMimeTypes (array)',
'xpack.cases.files.maxSize (number)',
'xpack.cases.markdownPlugins.lens (boolean)',
'xpack.cases.stack.enabled (boolean)',
'xpack.ccr.ui.enabled (boolean)',
'xpack.cloud.base_url (string)',
'xpack.cloud.cname (string)',
'xpack.cloud.deployment_url (string)',
'xpack.cloud.deployments_url (string)',
'xpack.cloud.is_elastic_staff_owned (boolean)',
'xpack.cloud.trial_end_date (string)',
'xpack.cloud_integrations.chat.chatURL (string)',
'xpack.cloud_integrations.chat.trialBuffer (number)',
'xpack.apm.serviceMapEnabled (boolean?)',
'xpack.apm.ui.enabled (boolean?)',
'xpack.apm.ui.maxTraceItems (number?)',
'xpack.apm.managedServiceUrl (string?|never)',
'xpack.apm.serverlessOnboarding (boolean?|never)',
'xpack.apm.latestAgentVersionsUrl (string?)',
'xpack.apm.featureFlags.agentConfigurationAvailable (boolean?|true?)',
'xpack.apm.featureFlags.configurableIndicesAvailable (boolean?|true?)',
'xpack.apm.featureFlags.infrastructureTabAvailable (boolean?|true?)',
'xpack.apm.featureFlags.infraUiAvailable (boolean?|true?)',
'xpack.apm.featureFlags.migrationToFleetAvailable (boolean?|true?)',
'xpack.apm.featureFlags.sourcemapApiAvailable (boolean?|true?)',
'xpack.apm.featureFlags.storageExplorerAvailable (boolean?|true?)',
'xpack.apm.featureFlags.profilingIntegrationAvailable (boolean?)',
'xpack.apm.serverless.enabled (true?|never)',
'xpack.observability_onboarding.serverless.enabled (true?|never)',
'xpack.cases.files.allowedMimeTypes (array?)',
'xpack.cases.files.maxSize (number?)',
'xpack.cases.markdownPlugins.lens (boolean?)',
'xpack.cases.stack.enabled (boolean?)',
'xpack.ccr.ui.enabled (boolean?)',
'xpack.cloud.base_url (string?)',
'xpack.cloud.cname (string?)',
'xpack.cloud.deployment_url (string?)',
'xpack.cloud.deployments_url (string?)',
'xpack.cloud.is_elastic_staff_owned (boolean?)',
'xpack.cloud.trial_end_date (string?)',
'xpack.cloud_integrations.chat.chatURL (string?)',
'xpack.cloud_integrations.chat.trialBuffer (number?)',
// No PII. This is an escape patch to override LaunchDarkly's flag resolution mechanism for testing or quick fix.
'xpack.cloud_integrations.experiments.flag_overrides (record)',
'xpack.cloud_integrations.experiments.flag_overrides (record?)',
// Commented because it's inside a schema conditional, and the test is not able to resolve it. But it's shared.
// Added here for documentation purposes.
// 'xpack.cloud_integrations.experiments.launch_darkly.client_id (string)',
// 'xpack.cloud_integrations.experiments.launch_darkly.client_log_level (string)',
'xpack.cloud_integrations.experiments.metadata_refresh_interval (duration)',
'xpack.cloud_integrations.full_story.org_id (any)',
'xpack.cloud_integrations.experiments.metadata_refresh_interval (duration?)',
'xpack.cloud_integrations.full_story.org_id (string|string?)',
// No PII. Just the list of event types we want to forward to FullStory.
'xpack.cloud_integrations.full_story.eventTypesAllowlist (array)',
'xpack.cloud_integrations.full_story.pageVarsDebounceTime (duration)',
'xpack.cloud.id (string)',
'xpack.cloud.organization_id (string)',
'xpack.cloud.organization_url (string)',
'xpack.cloud.billing_url (string)',
'xpack.cloud.profile_url (string)',
'xpack.cloud.performance_url (string)',
'xpack.cloud.users_and_roles_url (string)',
'xpack.cloud.projects_url (any)', // It's a string (any because schema.conditional)
'xpack.cloud_integrations.full_story.eventTypesAllowlist (array?)',
'xpack.cloud_integrations.full_story.pageVarsDebounceTime (duration?)',
'xpack.cloud.id (string?)',
'xpack.cloud.organization_id (string?)',
'xpack.cloud.organization_url (string?)',
'xpack.cloud.billing_url (string?)',
'xpack.cloud.profile_url (string?)',
'xpack.cloud.performance_url (string?)',
'xpack.cloud.users_and_roles_url (string?)',
'xpack.cloud.projects_url (string?|never)',
// can't be used to infer urls or customer id from the outside
'xpack.cloud.serverless.project_id (string)',
'xpack.cloud.serverless.project_name (string)',
'xpack.cloud.serverless.project_type (string)',
'xpack.cloud.serverless.orchestrator_target (string)',
'xpack.cloud.onboarding.default_solution (string)',
'xpack.discoverEnhanced.actions.exploreDataInChart.enabled (boolean)',
'xpack.discoverEnhanced.actions.exploreDataInContextMenu.enabled (boolean)',
'xpack.fleet.agents.enabled (boolean)',
'xpack.cloud.serverless.project_id (string?)',
'xpack.cloud.serverless.project_name (string?)',
'xpack.cloud.serverless.project_type (string?)',
'xpack.cloud.serverless.orchestrator_target (string?)',
'xpack.cloud.onboarding.default_solution (string?)',
'xpack.discoverEnhanced.actions.exploreDataInChart.enabled (boolean?)',
'xpack.discoverEnhanced.actions.exploreDataInContextMenu.enabled (boolean?)',
'xpack.fleet.agents.enabled (boolean?)',
'xpack.fleet.agentless.api.url (string)',
'xpack.fleet.enableExperimental (array)',
'xpack.fleet.internal.activeAgentsSoftLimit (number)',
'xpack.fleet.internal.fleetServerStandalone (boolean)',
'xpack.fleet.internal.onlyAllowAgentUpgradeToKnownVersions (boolean)',
'xpack.fleet.developer.maxAgentPoliciesWithInactivityTimeout (number)',
'xpack.global_search.search_timeout (duration)',
'xpack.global_search_bar.input_max_limit (number)',
'xpack.graph.canEditDrillDownUrls (boolean)',
'xpack.graph.savePolicy (alternatives)',
'xpack.ilm.ui.enabled (boolean)',
'xpack.index_management.ui.enabled (boolean)',
'xpack.infra.sources.default.fields.message (array)',
'xpack.index_management.enableTogglingDataRetention (any)', // It's a boolean (any because schema.conditional)
'xpack.fleet.enableExperimental (array?)',
'xpack.fleet.internal.activeAgentsSoftLimit (number?)',
'xpack.fleet.internal.fleetServerStandalone (boolean?)',
'xpack.fleet.internal.onlyAllowAgentUpgradeToKnownVersions (boolean?)',
'xpack.fleet.developer.maxAgentPoliciesWithInactivityTimeout (number?)',
'xpack.global_search.search_timeout (duration?)',
'xpack.global_search_bar.input_max_limit (number?)',
'xpack.graph.canEditDrillDownUrls (boolean?)',
'xpack.graph.savePolicy (none?|config?|configAndData?|configAndDataWithConsent?)',
'xpack.ilm.ui.enabled (boolean?)',
'xpack.index_management.ui.enabled (boolean?)',
'xpack.infra.sources.default.fields.message (array?)',
'xpack.index_management.enableTogglingDataRetention (boolean?|never)',
/**
* Feature flags bellow are conditional based on traditional/serverless offering
* and will all resolve to xpack.infra.featureFlags.* (boolean)
*/
'xpack.infra.featureFlags.metricsExplorerEnabled (any)',
'xpack.infra.featureFlags.customThresholdAlertsEnabled (any)',
'xpack.infra.featureFlags.osqueryEnabled (boolean)',
'xpack.infra.featureFlags.inventoryThresholdAlertRuleEnabled (any)',
'xpack.infra.featureFlags.metricThresholdAlertRuleEnabled (any)',
'xpack.infra.featureFlags.logThresholdAlertRuleEnabled (any)',
'xpack.infra.featureFlags.logsUIEnabled (any)',
'xpack.infra.featureFlags.alertsAndRulesDropdownEnabled (any)',
'xpack.infra.featureFlags.profilingEnabled (boolean)',
'xpack.infra.featureFlags.metricsExplorerEnabled (boolean?)',
'xpack.infra.featureFlags.customThresholdAlertsEnabled (boolean?)',
'xpack.infra.featureFlags.osqueryEnabled (boolean?)',
'xpack.infra.featureFlags.inventoryThresholdAlertRuleEnabled (boolean?)',
'xpack.infra.featureFlags.metricThresholdAlertRuleEnabled (boolean?)',
'xpack.infra.featureFlags.logThresholdAlertRuleEnabled (boolean?)',
'xpack.infra.featureFlags.logsUIEnabled (boolean?)',
'xpack.infra.featureFlags.alertsAndRulesDropdownEnabled (boolean?)',
'xpack.infra.featureFlags.profilingEnabled (boolean?)',
'xpack.index_management.enableIndexActions (any)',
'xpack.index_management.enableLegacyTemplates (any)',
'xpack.index_management.enableIndexStats (any)',
'xpack.index_management.enableDataStreamStats (any)',
'xpack.index_management.editableIndexSettings (any)',
'xpack.index_management.enableMappingsSourceFieldSection (any)',
'xpack.index_management.dev.enableSemanticText (boolean)',
'xpack.license_management.ui.enabled (boolean)',
'xpack.maps.preserveDrawingBuffer (boolean)',
'xpack.maps.showMapsInspectorAdapter (boolean)',
'xpack.index_management.enableIndexActions (boolean?|never)',
'xpack.index_management.enableLegacyTemplates (boolean?|never)',
'xpack.index_management.enableIndexStats (boolean?|never)',
'xpack.index_management.enableDataStreamStats (boolean?|never)',
'xpack.index_management.editableIndexSettings (all?|limited?|never)',
'xpack.index_management.enableMappingsSourceFieldSection (boolean?|never)',
'xpack.index_management.dev.enableSemanticText (boolean?)',
'xpack.license_management.ui.enabled (boolean?)',
'xpack.maps.preserveDrawingBuffer (boolean?)',
'xpack.maps.showMapsInspectorAdapter (boolean?)',
'xpack.ml.ad.enabled (boolean)',
'xpack.ml.dfa.enabled (boolean)',
'xpack.ml.nlp.enabled (boolean)',
'xpack.osquery.actionEnabled (boolean)',
'xpack.remote_clusters.ui.enabled (boolean)',
'xpack.osquery.actionEnabled (boolean?)',
'xpack.remote_clusters.ui.enabled (boolean?)',
/**
* NOTE: The Reporting plugin is currently disabled in functional tests (see test/functional/config.base.js).
* It will be re-enabled once #102552 is completed.
@ -315,54 +313,54 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
// '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.search.homepage.ui.enabled (boolean)',
'xpack.searchInferenceEndpoints.ui.enabled (boolean)',
'xpack.searchPlayground.ui.enabled (boolean)',
'xpack.security.loginAssistanceMessage (string)',
'xpack.security.sameSiteCookies (alternatives)',
'xpack.security.showInsecureClusterWarning (boolean)',
'xpack.security.showNavLinks (boolean)',
'xpack.security.ui (any)',
'xpack.security.roleManagementEnabled (any)',
'xpack.spaces.maxSpaces (number)',
'xpack.spaces.allowFeatureVisibility (any)',
'xpack.spaces.allowSolutionVisibility (any)',
'xpack.securitySolution.enableExperimental (array)',
'xpack.securitySolution.prebuiltRulesPackageVersion (string)',
'xpack.securitySolution.offeringSettings (record)',
'xpack.snapshot_restore.slm_ui.enabled (boolean)',
'xpack.snapshot_restore.ui.enabled (boolean)',
'xpack.stack_connectors.enableExperimental (array)',
'xpack.trigger_actions_ui.enableExperimental (array)',
'xpack.trigger_actions_ui.enableGeoTrackingThresholdAlert (boolean)',
'xpack.timelines.enableExperimental (array)',
'xpack.alerting.rules.run.alerts.max (number)',
'xpack.upgrade_assistant.featureSet.migrateSystemIndices (boolean)',
'xpack.upgrade_assistant.featureSet.mlSnapshots (boolean)',
'xpack.upgrade_assistant.featureSet.reindexCorrectiveActions (boolean)',
'xpack.upgrade_assistant.ui.enabled (boolean)',
'xpack.observability.unsafe.alertDetails.metrics.enabled (boolean)',
'xpack.observability.unsafe.alertDetails.logs.enabled (boolean)',
'xpack.observability.unsafe.alertDetails.uptime.enabled (boolean)',
'xpack.observability.unsafe.alertDetails.observability.enabled (boolean)',
'xpack.observability.unsafe.thresholdRule.enabled (any)', // conditional, is actually a boolean
'xpack.observability_onboarding.ui.enabled (boolean)',
'xpack.observabilityLogsExplorer.navigation.showAppLink (any)', // conditional, is actually a boolean
'share.new_version.enabled (boolean)',
'aiAssistantManagementSelection.preferredAIAssistantType (alternatives)',
'xpack.rollup.ui.enabled (boolean?)',
'xpack.saved_object_tagging.cache_refresh_interval (duration?)',
'xpack.search.homepage.ui.enabled (boolean?)',
'xpack.searchInferenceEndpoints.ui.enabled (boolean?)',
'xpack.searchPlayground.ui.enabled (boolean?)',
'xpack.security.loginAssistanceMessage (string?)',
'xpack.security.sameSiteCookies (Strict?|Lax?|None?)',
'xpack.security.showInsecureClusterWarning (boolean?)',
'xpack.security.showNavLinks (boolean?)',
'xpack.security.ui (object?|never)',
'xpack.security.roleManagementEnabled (boolean?|never)',
'xpack.spaces.maxSpaces (number?)',
'xpack.spaces.allowFeatureVisibility (false|boolean?)',
'xpack.spaces.allowSolutionVisibility (false|boolean?)',
'xpack.securitySolution.enableExperimental (array?)',
'xpack.securitySolution.prebuiltRulesPackageVersion (string?)',
'xpack.securitySolution.offeringSettings (record?)',
'xpack.snapshot_restore.slm_ui.enabled (boolean?)',
'xpack.snapshot_restore.ui.enabled (boolean?)',
'xpack.stack_connectors.enableExperimental (array?)',
'xpack.trigger_actions_ui.enableExperimental (array?)',
'xpack.trigger_actions_ui.enableGeoTrackingThresholdAlert (boolean?)',
'xpack.timelines.enableExperimental (array?)',
'xpack.alerting.rules.run.alerts.max (number?)',
'xpack.upgrade_assistant.featureSet.migrateSystemIndices (boolean?)',
'xpack.upgrade_assistant.featureSet.mlSnapshots (boolean?)',
'xpack.upgrade_assistant.featureSet.reindexCorrectiveActions (boolean?)',
'xpack.upgrade_assistant.ui.enabled (boolean?)',
'xpack.observability.unsafe.alertDetails.metrics.enabled (boolean?)',
'xpack.observability.unsafe.alertDetails.logs.enabled (boolean?)',
'xpack.observability.unsafe.alertDetails.uptime.enabled (boolean?)',
'xpack.observability.unsafe.alertDetails.observability.enabled (boolean?)',
'xpack.observability.unsafe.thresholdRule.enabled (boolean?)',
'xpack.observability_onboarding.ui.enabled (boolean?)',
'xpack.observabilityLogsExplorer.navigation.showAppLink (boolean?|never)',
'share.new_version.enabled (boolean?)',
'aiAssistantManagementSelection.preferredAIAssistantType (default?|never?|observability?)',
/**
* Rule form V2 feature flags
*/
'discover.experimental.ruleFormV2Enabled (boolean)',
'xpack.infra.featureFlags.ruleFormV2Enabled (boolean)',
'xpack.legacy_uptime.experimental.ruleFormV2Enabled (boolean)',
'discover.experimental.ruleFormV2Enabled (boolean?)',
'xpack.infra.featureFlags.ruleFormV2Enabled (boolean?)',
'xpack.legacy_uptime.experimental.ruleFormV2Enabled (boolean?)',
'xpack.ml.experimental.ruleFormV2.enabled (boolean)',
'xpack.transform.experimental.ruleFormV2Enabled (boolean)',
'xpack.apm.featureFlags.ruleFormV2Enabled (boolean)',
'xpack.observability.unsafe.ruleFormV2.enabled (boolean)',
'xpack.slo.experimental.ruleFormV2.enabled (boolean)',
'xpack.transform.experimental.ruleFormV2Enabled (boolean?)',
'xpack.apm.featureFlags.ruleFormV2Enabled (boolean?)',
'xpack.observability.unsafe.ruleFormV2.enabled (boolean?)',
'xpack.slo.experimental.ruleFormV2.enabled (boolean?)',
/**/
];
// We don't assert that actualExposedConfigKeys and expectedExposedConfigKeys are equal, because test failure messages with large
@ -401,37 +399,37 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
// 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)',
'xpack.security.showNavLinks (boolean)',
'xpack.security.ui (any)',
'xpack.security.roleManagementEnabled (any)',
'xpack.security.loginAssistanceMessage (string?)',
'xpack.security.sameSiteCookies (Strict?|Lax?|None?)',
'xpack.security.showInsecureClusterWarning (boolean?)',
'xpack.security.showNavLinks (boolean?)',
'xpack.security.ui (object?|never)',
'xpack.security.roleManagementEnabled (boolean?|never)',
'telemetry.allowChangingOptInStatus (boolean)',
'telemetry.appendServerlessChannelsSuffix (any)', // It's a boolean (any because schema.conditional)
'telemetry.banner (boolean)',
'telemetry.labels.branch (string)',
'telemetry.labels.ciBuildId (string)',
'telemetry.labels.ciBuildJobId (string)',
'telemetry.labels.ciBuildNumber (number)',
'telemetry.labels.environment (string)',
'telemetry.labels.ftrConfig (string)',
'telemetry.labels.gitRev (string)',
'telemetry.labels.isPr (boolean)',
'telemetry.labels.journeyName (string)',
'telemetry.labels.prId (number)',
'telemetry.labels.testBuildId (string)',
'telemetry.labels.testJobId (string)',
'telemetry.labels.ciBuildName (string)',
'telemetry.labels.performancePhase (string)',
'telemetry.labels.serverless (any)', // It's the project type (string), claims any because schema.conditional. Can only be set on Serverless.
'telemetry.hidePrivacyStatement (boolean)',
'telemetry.optIn (boolean)',
'telemetry.sendUsageFrom (alternatives)',
'telemetry.sendUsageTo (any)',
'usageCollection.uiCounters.debug (boolean)',
'usageCollection.uiCounters.enabled (boolean)',
'telemetry.allowChangingOptInStatus (boolean?)',
'telemetry.appendServerlessChannelsSuffix (true?|false?)',
'telemetry.banner (boolean?)',
'telemetry.labels.branch (string?)',
'telemetry.labels.ciBuildId (string?)',
'telemetry.labels.ciBuildJobId (string?)',
'telemetry.labels.ciBuildNumber (number?)',
'telemetry.labels.environment (string?)',
'telemetry.labels.ftrConfig (string?)',
'telemetry.labels.gitRev (string?)',
'telemetry.labels.isPr (boolean?)',
'telemetry.labels.journeyName (string?)',
'telemetry.labels.prId (number?)',
'telemetry.labels.testBuildId (string?)',
'telemetry.labels.testJobId (string?)',
'telemetry.labels.ciBuildName (string?)',
'telemetry.labels.performancePhase (string?)',
'telemetry.labels.serverless (string?|never)', // Can only be set on Serverless.
'telemetry.hidePrivacyStatement (boolean?)',
'telemetry.optIn (boolean?)',
'telemetry.sendUsageFrom (server?|browser?)',
'telemetry.sendUsageTo (prod?|staging?)',
'usageCollection.uiCounters.debug (boolean?)',
'usageCollection.uiCounters.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