mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
# Backport This will backport the following commits from `main` to `9.0`: - [[Security Solution] Allow disabling experimental features via config (#217363)](https://github.com/elastic/kibana/pull/217363) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Sergi Massaneda","email":"sergi.massaneda@elastic.co"},"sourceCommit":{"committedDate":"2025-04-16T12:09:28Z","message":"[Security Solution] Allow disabling experimental features via config (#217363)\n\n## Summary\n\nThis PR adds support for disabling experimental features using the\nexisting `xpack.securitySolution.enableExperimental` configuration.\n\nThis solves the problem of not being able to disable a feature by config\nonce the feature has been enabled by default.\n\n### The Challenge \n\nWhen we start developing a feature under an experimental flag we always\nfollow the same steps:\n\n1 - Create the experimental flag disabled by default + enable it via\nconfig for testing\n2 - Implement the feature\n3 - Enable the experimental flag by default when we want to release the\nfeature.\n4 - Deployments can disable the feature via config (as a safety\nmeasure).\n5 - Remove the experimental flag after some time.\n\nWe start by creating the flag disabled by default while we implement it.\nIn `experimental_features.ts`:\n```ts\nexport const allowedExperimentalValues = Object.freeze({\n myFeatureEnabled: false,\n [...]\n```\nAnd enable it via config with:\n```yml\nxpack.securitySolution.enableExperimental:\n - myFeatureEnabled\n```\n\nOnce the implementation is done and the experimental flag can be enabled\nby default, we have to do a trick:\nSince the `xpack.securitySolution.enableExperimental` config can only\nturn flags to _true_, instead of setting `myFeatureEnabled: true`, what\nwe have to do is rename the flag to `myFeatureDisabled` and keep the\nvalue as _false_:\n\n```ts\nexport const allowedExperimentalValues = Object.freeze({\n myFeatureDisabled: false,\n [...]\n```\nThen we also need to do a code refactor to update all the places in the\ncode where the flag was checked: `if (myFeatureEnabled)` -> `if\n(!myFeatureDisabled)`\n\nThis way, we have the option of disabling the feature via config (in\ncase something goes wrong):\n```yml\nxpack.securitySolution.enableExperimental:\n - myFeatureDisabled\n```\n\n### A solution\n\nThis PR introduces the possibility to turn a flag to _false_ using the\nsame `xpack.securitySolution.enableExperimental` config. This was\npreferable to introducing a new config since this one is already\nwhitelisted in Cloud UI, can be easily overritten in deployments, and\nalso because people are used to it.\n\nWith these changes, the first two steps would be the same, with the\ndifference that we won't need to have the _Enabled_ or _Disabled_ word\nat the end of the flag name. It could be just the feature name, in\n`experimental_features.ts`:\n```ts\nexport const allowedExperimentalValues = Object.freeze({\n myFeature: false,\n [...]\n```\n\nAnd when we need to enable the feature by default, we can just turn it\nto `true`:\n```ts\nexport const allowedExperimentalValues = Object.freeze({\n myFeature: true,\n [...]\n```\nNo tedious refactor or confusing naming would be required. \n\nThen, in case we need to disable the feature in a production deployment\nfor some reason, we could just do this via config :\n```yml\nxpack.securitySolution.enableExperimental:\n - disable:myFeature\n```\n\n---------\n\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"937dbba41ef6d52b1d060f03f0e2d9a99247016e","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team: SecuritySolution","backport:version","v8.18.0","v9.1.0","v8.19.0","v9.0.1"],"title":"[Security Solution] Allow disabling experimental features via config","number":217363,"url":"https://github.com/elastic/kibana/pull/217363","mergeCommit":{"message":"[Security Solution] Allow disabling experimental features via config (#217363)\n\n## Summary\n\nThis PR adds support for disabling experimental features using the\nexisting `xpack.securitySolution.enableExperimental` configuration.\n\nThis solves the problem of not being able to disable a feature by config\nonce the feature has been enabled by default.\n\n### The Challenge \n\nWhen we start developing a feature under an experimental flag we always\nfollow the same steps:\n\n1 - Create the experimental flag disabled by default + enable it via\nconfig for testing\n2 - Implement the feature\n3 - Enable the experimental flag by default when we want to release the\nfeature.\n4 - Deployments can disable the feature via config (as a safety\nmeasure).\n5 - Remove the experimental flag after some time.\n\nWe start by creating the flag disabled by default while we implement it.\nIn `experimental_features.ts`:\n```ts\nexport const allowedExperimentalValues = Object.freeze({\n myFeatureEnabled: false,\n [...]\n```\nAnd enable it via config with:\n```yml\nxpack.securitySolution.enableExperimental:\n - myFeatureEnabled\n```\n\nOnce the implementation is done and the experimental flag can be enabled\nby default, we have to do a trick:\nSince the `xpack.securitySolution.enableExperimental` config can only\nturn flags to _true_, instead of setting `myFeatureEnabled: true`, what\nwe have to do is rename the flag to `myFeatureDisabled` and keep the\nvalue as _false_:\n\n```ts\nexport const allowedExperimentalValues = Object.freeze({\n myFeatureDisabled: false,\n [...]\n```\nThen we also need to do a code refactor to update all the places in the\ncode where the flag was checked: `if (myFeatureEnabled)` -> `if\n(!myFeatureDisabled)`\n\nThis way, we have the option of disabling the feature via config (in\ncase something goes wrong):\n```yml\nxpack.securitySolution.enableExperimental:\n - myFeatureDisabled\n```\n\n### A solution\n\nThis PR introduces the possibility to turn a flag to _false_ using the\nsame `xpack.securitySolution.enableExperimental` config. This was\npreferable to introducing a new config since this one is already\nwhitelisted in Cloud UI, can be easily overritten in deployments, and\nalso because people are used to it.\n\nWith these changes, the first two steps would be the same, with the\ndifference that we won't need to have the _Enabled_ or _Disabled_ word\nat the end of the flag name. It could be just the feature name, in\n`experimental_features.ts`:\n```ts\nexport const allowedExperimentalValues = Object.freeze({\n myFeature: false,\n [...]\n```\n\nAnd when we need to enable the feature by default, we can just turn it\nto `true`:\n```ts\nexport const allowedExperimentalValues = Object.freeze({\n myFeature: true,\n [...]\n```\nNo tedious refactor or confusing naming would be required. \n\nThen, in case we need to disable the feature in a production deployment\nfor some reason, we could just do this via config :\n```yml\nxpack.securitySolution.enableExperimental:\n - disable:myFeature\n```\n\n---------\n\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"937dbba41ef6d52b1d060f03f0e2d9a99247016e"}},"sourceBranch":"main","suggestedTargetBranches":["9.0","8.18","8.x"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/217363","number":217363,"mergeCommit":{"message":"[Security Solution] Allow disabling experimental features via config (#217363)\n\n## Summary\n\nThis PR adds support for disabling experimental features using the\nexisting `xpack.securitySolution.enableExperimental` configuration.\n\nThis solves the problem of not being able to disable a feature by config\nonce the feature has been enabled by default.\n\n### The Challenge \n\nWhen we start developing a feature under an experimental flag we always\nfollow the same steps:\n\n1 - Create the experimental flag disabled by default + enable it via\nconfig for testing\n2 - Implement the feature\n3 - Enable the experimental flag by default when we want to release the\nfeature.\n4 - Deployments can disable the feature via config (as a safety\nmeasure).\n5 - Remove the experimental flag after some time.\n\nWe start by creating the flag disabled by default while we implement it.\nIn `experimental_features.ts`:\n```ts\nexport const allowedExperimentalValues = Object.freeze({\n myFeatureEnabled: false,\n [...]\n```\nAnd enable it via config with:\n```yml\nxpack.securitySolution.enableExperimental:\n - myFeatureEnabled\n```\n\nOnce the implementation is done and the experimental flag can be enabled\nby default, we have to do a trick:\nSince the `xpack.securitySolution.enableExperimental` config can only\nturn flags to _true_, instead of setting `myFeatureEnabled: true`, what\nwe have to do is rename the flag to `myFeatureDisabled` and keep the\nvalue as _false_:\n\n```ts\nexport const allowedExperimentalValues = Object.freeze({\n myFeatureDisabled: false,\n [...]\n```\nThen we also need to do a code refactor to update all the places in the\ncode where the flag was checked: `if (myFeatureEnabled)` -> `if\n(!myFeatureDisabled)`\n\nThis way, we have the option of disabling the feature via config (in\ncase something goes wrong):\n```yml\nxpack.securitySolution.enableExperimental:\n - myFeatureDisabled\n```\n\n### A solution\n\nThis PR introduces the possibility to turn a flag to _false_ using the\nsame `xpack.securitySolution.enableExperimental` config. This was\npreferable to introducing a new config since this one is already\nwhitelisted in Cloud UI, can be easily overritten in deployments, and\nalso because people are used to it.\n\nWith these changes, the first two steps would be the same, with the\ndifference that we won't need to have the _Enabled_ or _Disabled_ word\nat the end of the flag name. It could be just the feature name, in\n`experimental_features.ts`:\n```ts\nexport const allowedExperimentalValues = Object.freeze({\n myFeature: false,\n [...]\n```\n\nAnd when we need to enable the feature by default, we can just turn it\nto `true`:\n```ts\nexport const allowedExperimentalValues = Object.freeze({\n myFeature: true,\n [...]\n```\nNo tedious refactor or confusing naming would be required. \n\nThen, in case we need to disable the feature in a production deployment\nfor some reason, we could just do this via config :\n```yml\nxpack.securitySolution.enableExperimental:\n - disable:myFeature\n```\n\n---------\n\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"937dbba41ef6d52b1d060f03f0e2d9a99247016e"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Sergi Massaneda <sergi.massaneda@elastic.co> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
3fc06a8092
commit
25cef6d35b
1 changed files with 10 additions and 3 deletions
|
@ -263,9 +263,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
|
||||
|
@ -276,11 +279,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