Skip to content

Commit

Permalink
[Security Solution] Support experimental features in timelines (#189028)
Browse files Browse the repository at this point in the history
## Summary

Adding generic support for experimental features in timelines

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
lgestc and kibanamachine committed Jul 26, 2024
1 parent 7e5907e commit 7db2868
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -935,4 +935,3 @@ components:
type: http
security:
- BasicAuth: []
tags: !<tag:yaml.org,2002:js/undefined> ''
Original file line number Diff line number Diff line change
Expand Up @@ -863,4 +863,3 @@ components:
type: http
security:
- BasicAuth: []
tags: !<tag:yaml.org,2002:js/undefined> ''
47 changes: 47 additions & 0 deletions x-pack/plugins/timelines/common/experimental_features.ts
Original file line number Diff line number Diff line change
@@ -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<T> = { -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<Partial<ExperimentalFeatures>> = {};
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,
};
};
10 changes: 10 additions & 0 deletions x-pack/plugins/timelines/server/config.ts
Original file line number Diff line number Diff line change
@@ -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[];
}
29 changes: 28 additions & 1 deletion x-pack/plugins/timelines/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,38 @@
* 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');
return new TimelinesPlugin(initializerContext);
}

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<ConfigSchema> = {
exposeToBrowser: {
enableExperimental: true,
},
schema: configSchema,
};
7 changes: 7 additions & 0 deletions x-pack/plugins/timelines/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<TimelinesPluginUI, TimelinesPluginStart, SetupPlugins, StartPlugins>
Expand All @@ -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<ConfigSchema>().enableExperimental
);
}

public setup(core: CoreSetup<StartPlugins, TimelinesPluginStart>, plugins: SetupPlugins) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<z.input<typeof searchStrategyRequestSchema>, any> => {
const es = data.search.getSearchStrategy(ENHANCED_ES_SEARCH_STRATEGY);
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/timelines/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -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/**/*"
Expand Down

0 comments on commit 7db2868

Please sign in to comment.