diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 27addbfc274a29..a551030b943ba0 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -336,6 +336,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { '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)', diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml index 22979d62e09338..c23158972fd777 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml @@ -935,4 +935,3 @@ components: type: http security: - BasicAuth: [] -tags: ! '' diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml index 99627f8bd8a9e7..5b6a8ffc8a1893 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_endpoint_management_api_2023_10_31.bundled.schema.yaml @@ -863,4 +863,3 @@ components: type: http security: - BasicAuth: [] -tags: ! '' diff --git a/x-pack/plugins/timelines/common/experimental_features.ts b/x-pack/plugins/timelines/common/experimental_features.ts new file mode 100644 index 00000000000000..9f56236292c1b9 --- /dev/null +++ b/x-pack/plugins/timelines/common/experimental_features.ts @@ -0,0 +1,47 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const allowedExperimentalValues = Object.freeze({ + // NOTE: remove this after some actual flags are added, without it line 36 fails ts validation + sample: false, +}); + +export type ExperimentalFeatures = { [K in keyof typeof allowedExperimentalValues]: boolean }; + +const allowedKeys = Object.keys(allowedExperimentalValues); + +type Mutable = { -readonly [P in keyof T]: T[P] }; + +/** + * Parses the string value used in `xpack.timelines.enableExperimental` kibana configuration, + * which should be a string of values delimited by a comma (`,`) + * + * @param configValue + * @throws SecuritySolutionInvalidExperimentalValue + */ +export const parseExperimentalConfigValue = ( + configValue: string[] +): { features: ExperimentalFeatures; invalid: string[] } => { + const enabledFeatures: Mutable> = {}; + const invalidKeys: string[] = []; + + for (const value of configValue) { + if (!allowedKeys.includes(value as keyof ExperimentalFeatures)) { + invalidKeys.push(value); + } else { + enabledFeatures[value as keyof ExperimentalFeatures] = true; + } + } + + return { + features: { + ...allowedExperimentalValues, + ...enabledFeatures, + }, + invalid: invalidKeys, + }; +}; diff --git a/x-pack/plugins/timelines/server/config.ts b/x-pack/plugins/timelines/server/config.ts new file mode 100644 index 00000000000000..9cf2c371e36858 --- /dev/null +++ b/x-pack/plugins/timelines/server/config.ts @@ -0,0 +1,10 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface ConfigSchema { + enableExperimental: string[]; +} diff --git a/x-pack/plugins/timelines/server/index.ts b/x-pack/plugins/timelines/server/index.ts index acdcc26a0a1aa1..929be7a34ab427 100644 --- a/x-pack/plugins/timelines/server/index.ts +++ b/x-pack/plugins/timelines/server/index.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { PluginInitializerContext } from '@kbn/core/server'; +import { PluginConfigDescriptor, PluginInitializerContext } from '@kbn/core/server'; +import { schema } from '@kbn/config-schema'; +import { ConfigSchema } from './config'; export async function plugin(initializerContext: PluginInitializerContext) { const { TimelinesPlugin } = await import('./plugin'); @@ -13,3 +15,28 @@ export async function plugin(initializerContext: PluginInitializerContext) { } export type { TimelinesPluginUI, TimelinesPluginStart } from './types'; + +const configSchema = schema.object({ + /** + * For internal use. A list of string values (comma delimited) that will enable experimental + * type of functionality that is not yet released. Valid values for this settings need to + * be defined in: + * `x-pack/plugins/timelines/common/experimental_features.ts` + * under the `allowedExperimentalValues` object + * + * @example + * xpack.timelines.enableExperimental: + * - someCrazyFeature + * - someEvenCrazierFeature + */ + enableExperimental: schema.arrayOf(schema.string(), { + defaultValue: () => [], + }), +}); + +export const config: PluginConfigDescriptor = { + exposeToBrowser: { + enableExperimental: true, + }, + schema: configSchema, +}; diff --git a/x-pack/plugins/timelines/server/plugin.ts b/x-pack/plugins/timelines/server/plugin.ts index 619c66a05ee304..4550cfa7348a6d 100644 --- a/x-pack/plugins/timelines/server/plugin.ts +++ b/x-pack/plugins/timelines/server/plugin.ts @@ -12,6 +12,8 @@ import { SetupPlugins, StartPlugins, TimelinesPluginUI, TimelinesPluginStart } f import { timelineSearchStrategyProvider } from './search_strategy/timeline'; import { timelineEqlSearchStrategyProvider } from './search_strategy/timeline/eql'; import { indexFieldsProvider } from './search_strategy/index_fields'; +import { parseExperimentalConfigValue } from '../common/experimental_features'; +import { ConfigSchema } from './config'; export class TimelinesPlugin implements Plugin @@ -21,6 +23,11 @@ export class TimelinesPlugin constructor(initializerContext: PluginInitializerContext) { this.logger = initializerContext.logger.get(); + + // NOTE: underscored to skip lint warning, but it can be used to implement experimental features behind a flag + const { features: _experimentalFeatures } = parseExperimentalConfigValue( + initializerContext.config.get().enableExperimental + ); } public setup(core: CoreSetup, plugins: SetupPlugins) { diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/index.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/index.ts index e3166f770174af..4656af94931904 100644 --- a/x-pack/plugins/timelines/server/search_strategy/timeline/index.ts +++ b/x-pack/plugins/timelines/server/search_strategy/timeline/index.ts @@ -17,6 +17,7 @@ import { ENHANCED_ES_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; import { Logger } from '@kbn/logging'; import { z } from 'zod'; + import { searchStrategyRequestSchema } from '../../../common/api/search_strategy'; import { TimelineFactoryQueryTypes, @@ -30,7 +31,7 @@ import { isAggCardinalityAggregate } from './factory/helpers/is_agg_cardinality_ export const timelineSearchStrategyProvider = ( data: PluginStart, logger: Logger, - security?: SecurityPluginSetup + _security?: SecurityPluginSetup // eslint-disable-next-line @typescript-eslint/no-explicit-any ): ISearchStrategy, any> => { const es = data.search.getSearchStrategy(ENHANCED_ES_SEARCH_STRATEGY); diff --git a/x-pack/plugins/timelines/tsconfig.json b/x-pack/plugins/timelines/tsconfig.json index 3101c2b3992ba3..343c0eaad28620 100644 --- a/x-pack/plugins/timelines/tsconfig.json +++ b/x-pack/plugins/timelines/tsconfig.json @@ -37,7 +37,8 @@ "@kbn/search-errors", "@kbn/search-types", "@kbn/react-kibana-mount", - "@kbn/field-formats-plugin" + "@kbn/field-formats-plugin", + "@kbn/config-schema" ], "exclude": [ "target/**/*"