mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Security Solution] Allow disabling experimental features via config (#217363)
## Summary This PR adds support for disabling experimental features using the existing `xpack.securitySolution.enableExperimental` configuration. This solves the problem of not being able to disable a feature by config once the feature has been enabled by default. ### The Challenge When we start developing a feature under an experimental flag we always follow the same steps: 1 - Create the experimental flag disabled by default + enable it via config for testing 2 - Implement the feature 3 - Enable the experimental flag by default when we want to release the feature. 4 - Deployments can disable the feature via config (as a safety measure). 5 - Remove the experimental flag after some time. We start by creating the flag disabled by default while we implement it. In `experimental_features.ts`: ```ts export const allowedExperimentalValues = Object.freeze({ myFeatureEnabled: false, [...] ``` And enable it via config with: ```yml xpack.securitySolution.enableExperimental: - myFeatureEnabled ``` Once the implementation is done and the experimental flag can be enabled by default, we have to do a trick: Since the `xpack.securitySolution.enableExperimental` config can only turn flags to _true_, instead of setting `myFeatureEnabled: true`, what we have to do is rename the flag to `myFeatureDisabled` and keep the value as _false_: ```ts export const allowedExperimentalValues = Object.freeze({ myFeatureDisabled: false, [...] ``` Then we also need to do a code refactor to update all the places in the code where the flag was checked: `if (myFeatureEnabled)` -> `if (!myFeatureDisabled)` This way, we have the option of disabling the feature via config (in case something goes wrong): ```yml xpack.securitySolution.enableExperimental: - myFeatureDisabled ``` ### A solution This PR introduces the possibility to turn a flag to _false_ using the same `xpack.securitySolution.enableExperimental` config. This was preferable to introducing a new config since this one is already whitelisted in Cloud UI, can be easily overritten in deployments, and also because people are used to it. With these changes, the first two steps would be the same, with the difference that we won't need to have the _Enabled_ or _Disabled_ word at the end of the flag name. It could be just the feature name, in `experimental_features.ts`: ```ts export const allowedExperimentalValues = Object.freeze({ myFeature: false, [...] ``` And when we need to enable the feature by default, we can just turn it to `true`: ```ts export const allowedExperimentalValues = Object.freeze({ myFeature: true, [...] ``` No tedious refactor or confusing naming would be required. Then, in case we need to disable the feature in a production deployment for some reason, we could just do this via config : ```yml xpack.securitySolution.enableExperimental: - disable:myFeature ``` --------- Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
b91da375a3
commit
937dbba41e
1 changed files with 10 additions and 3 deletions
|
@ -276,9 +276,12 @@ type Mutable<T> = { -readonly [P in keyof T]: T[P] };
|
|||
|
||||
const allowedKeys = Object.keys(allowedExperimentalValues) as Readonly<ExperimentalConfigKeys>;
|
||||
|
||||
const disableExperimentalPrefix = 'disable:' as const;
|
||||
|
||||
/**
|
||||
* Parses the string value used in `xpack.securitySolution.enableExperimental` kibana configuration,
|
||||
* which should be a string of values delimited by a comma (`,`)
|
||||
* which should be an array of strings corresponding to allowedExperimentalValues keys.
|
||||
* Use the `disable:` prefix to disable a feature.
|
||||
*
|
||||
* @param configValue
|
||||
* @throws SecuritySolutionInvalidExperimentalValue
|
||||
|
@ -289,11 +292,15 @@ export const parseExperimentalConfigValue = (
|
|||
const enabledFeatures: Mutable<Partial<ExperimentalFeatures>> = {};
|
||||
const invalidKeys: string[] = [];
|
||||
|
||||
for (const value of configValue) {
|
||||
for (let value of configValue) {
|
||||
const isDisabled = value.startsWith(disableExperimentalPrefix);
|
||||
if (isDisabled) {
|
||||
value = value.replace(disableExperimentalPrefix, '');
|
||||
}
|
||||
if (!allowedKeys.includes(value as keyof ExperimentalFeatures)) {
|
||||
invalidKeys.push(value);
|
||||
} else {
|
||||
enabledFeatures[value as keyof ExperimentalFeatures] = true;
|
||||
enabledFeatures[value as keyof ExperimentalFeatures] = !isDisabled;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue