-
Notifications
You must be signed in to change notification settings - Fork 8.5k
[Config Service] Use stripUnknownKeys when checking enabled flags
#201579
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12,7 +12,7 @@ import { SchemaTypeError, Type, ValidationError } from '@kbn/config-schema'; | |||||||||||||||||||||||||||||||||||||||||||||||
| import { cloneDeep, isEqual, merge, unset } from 'lodash'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { set } from '@kbn/safer-lodash-set'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { BehaviorSubject, combineLatest, firstValueFrom, Observable, identity } from 'rxjs'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { distinctUntilChanged, first, map, shareReplay, tap } from 'rxjs'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { distinctUntilChanged, map, shareReplay, tap } from 'rxjs'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { Logger, LoggerFactory } from '@kbn/logging'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { getDocLinks, DocLinks } from '@kbn/doc-links'; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -209,10 +209,31 @@ export class ConfigService { | |||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error(`No validation schema has been defined for [${namespace}]`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const validatedConfig = hasSchema | ||||||||||||||||||||||||||||||||||||||||||||||||
| ? await this.atPath<{ enabled?: boolean }>(path).pipe(first()).toPromise() | ||||||||||||||||||||||||||||||||||||||||||||||||
| let validatedConfig = hasSchema | ||||||||||||||||||||||||||||||||||||||||||||||||
| ? await firstValueFrom( | ||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I took the opportunity to change the deprecated usage of |
||||||||||||||||||||||||||||||||||||||||||||||||
| this.getValidatedConfigAtPath$( | ||||||||||||||||||||||||||||||||||||||||||||||||
| path, | ||||||||||||||||||||||||||||||||||||||||||||||||
| // At this point we don't care about how valid the config is: we just want to read `enabled` | ||||||||||||||||||||||||||||||||||||||||||||||||
| { stripUnknownKeys: true } | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) as Observable<{ enabled?: boolean }>, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { defaultValue: undefined } | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||
| : undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Special use case: when the provided config includes `enabled` and the validated config doesn't, | ||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is only at the top level of the object? Also could we add a test case for this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the existing test that reminded me that I would introduce a regression with simply using kibana/packages/kbn-config/src/config_service.test.ts Lines 352 to 374 in 3daaaa5
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // it's quite likely that's not an allowed config and it should fail. | ||||||||||||||||||||||||||||||||||||||||||||||||
| // Applying "normal" validation (not stripping unknowns) in that case. | ||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||
| hasSchema && | ||||||||||||||||||||||||||||||||||||||||||||||||
| typeof config.get(path)?.enabled !== 'undefined' && | ||||||||||||||||||||||||||||||||||||||||||||||||
| typeof validatedConfig?.enabled === 'undefined' | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| validatedConfig = await firstValueFrom( | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.getValidatedConfigAtPath$(path) as Observable<{ enabled?: boolean }>, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { defaultValue: undefined } | ||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+223
to
+235
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had to add this special use case since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes sense, although it's possible that the validation error may contain more than just "enabled"... perhaps we can catch and throw a more specific message here about the special "enabled" setting? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great point! I created #202490 for us to discuss the new potential message. |
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const isDisabled = validatedConfig?.enabled === false; | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (isDisabled) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| // If the plugin is explicitly disabled, we mark the entire plugin | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -325,7 +346,13 @@ export class ConfigService { | |||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| private validateAtPath(path: ConfigPath, config: Record<string, unknown>) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| private validateAtPath( | ||||||||||||||||||||||||||||||||||||||||||||||||
| path: ConfigPath, | ||||||||||||||||||||||||||||||||||||||||||||||||
| config: Record<string, unknown>, | ||||||||||||||||||||||||||||||||||||||||||||||||
| validateOptions?: { stripUnknownKeys?: boolean } | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const stripUnknownKeys = validateOptions?.stripUnknownKeys || this.stripUnknownKeys; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const namespace = pathToString(path); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const schema = this.schemas.get(namespace); | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (!schema) { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -340,18 +367,21 @@ export class ConfigService { | |||||||||||||||||||||||||||||||||||||||||||||||
| ...this.env.packageInfo, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| `config validation of [${namespace}]`, | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.stripUnknownKeys ? { stripUnknownKeys: this.stripUnknownKeys } : {} | ||||||||||||||||||||||||||||||||||||||||||||||||
| stripUnknownKeys ? { stripUnknownKeys } : {} | ||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| private getValidatedConfigAtPath$( | ||||||||||||||||||||||||||||||||||||||||||||||||
| path: ConfigPath, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { ignoreUnchanged = true }: { ignoreUnchanged?: boolean } = {} | ||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||
| ignoreUnchanged = true, | ||||||||||||||||||||||||||||||||||||||||||||||||
| stripUnknownKeys, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }: { ignoreUnchanged?: boolean; stripUnknownKeys?: boolean } = {} | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return this.config$.pipe( | ||||||||||||||||||||||||||||||||||||||||||||||||
| map((config) => config.get(path)), | ||||||||||||||||||||||||||||||||||||||||||||||||
| ignoreUnchanged ? distinctUntilChanged(isEqual) : identity, | ||||||||||||||||||||||||||||||||||||||||||||||||
| map((config) => this.validateAtPath(path, config)) | ||||||||||||||||||||||||||||||||||||||||||||||||
| map((config) => this.validateAtPath(path, config, { stripUnknownKeys })) | ||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
proving that
stripUnknownKeysworks as intended