diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index df64d99949b9c..a53f01d6082cc 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -480,6 +480,7 @@ packages/kbn-managed-vscode-config @elastic/kibana-operations packages/kbn-managed-vscode-config-cli @elastic/kibana-operations packages/kbn-management/cards_navigation @elastic/platform-deployment-management src/plugins/management @elastic/platform-deployment-management +packages/kbn-management/settings/setting_ids @elastic/appex-sharedux @elastic/platform-deployment-management packages/kbn-management/settings/section_registry @elastic/appex-sharedux @elastic/platform-deployment-management packages/kbn-management/storybook/config @elastic/platform-deployment-management test/plugin_functional/plugins/management_test_plugin @elastic/kibana-app-services @@ -633,9 +634,13 @@ packages/kbn-securitysolution-utils @elastic/security-detection-engine packages/kbn-server-http-tools @elastic/kibana-core packages/kbn-server-route-repository @elastic/apm-ui x-pack/plugins/serverless @elastic/appex-sharedux +packages/serverless/settings/common @elastic/appex-sharedux @elastic/platform-deployment-management x-pack/plugins/serverless_observability @elastic/appex-sharedux @elastic/apm-ui +packages/serverless/settings/observability_project @elastic/appex-sharedux @elastic/apm-ui @elastic/platform-deployment-management packages/serverless/project_switcher @elastic/appex-sharedux x-pack/plugins/serverless_search @elastic/enterprise-search-frontend +packages/serverless/settings/search_project @elastic/enterprise-search-frontend @elastic/platform-deployment-management +packages/serverless/settings/security_project @elastic/security-solution @elastic/platform-deployment-management packages/serverless/storybook/config @elastic/appex-sharedux packages/serverless/types @elastic/appex-sharedux test/plugin_functional/plugins/session_notifications @elastic/kibana-core diff --git a/package.json b/package.json index 14cd4677b26b6..b02c4b9f83623 100644 --- a/package.json +++ b/package.json @@ -500,6 +500,7 @@ "@kbn/logstash-plugin": "link:x-pack/plugins/logstash", "@kbn/management-cards-navigation": "link:packages/kbn-management/cards_navigation", "@kbn/management-plugin": "link:src/plugins/management", + "@kbn/management-settings-ids": "link:packages/kbn-management/settings/setting_ids", "@kbn/management-settings-section-registry": "link:packages/kbn-management/settings/section_registry", "@kbn/management-test-plugin": "link:test/plugin_functional/plugins/management_test_plugin", "@kbn/mapbox-gl": "link:packages/kbn-mapbox-gl", @@ -638,9 +639,13 @@ "@kbn/server-http-tools": "link:packages/kbn-server-http-tools", "@kbn/server-route-repository": "link:packages/kbn-server-route-repository", "@kbn/serverless": "link:x-pack/plugins/serverless", + "@kbn/serverless-common-settings": "link:packages/serverless/settings/common", "@kbn/serverless-observability": "link:x-pack/plugins/serverless_observability", + "@kbn/serverless-observability-settings": "link:packages/serverless/settings/observability_project", "@kbn/serverless-project-switcher": "link:packages/serverless/project_switcher", "@kbn/serverless-search": "link:x-pack/plugins/serverless_search", + "@kbn/serverless-search-settings": "link:packages/serverless/settings/search_project", + "@kbn/serverless-security-settings": "link:packages/serverless/settings/security_project", "@kbn/serverless-types": "link:packages/serverless/types", "@kbn/session-notifications-plugin": "link:test/plugin_functional/plugins/session_notifications", "@kbn/session-view-plugin": "link:x-pack/plugins/session_view", diff --git a/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_setup.mock.ts b/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_setup.mock.ts index 5397bc154f862..0436e677a7e64 100644 --- a/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_setup.mock.ts +++ b/packages/core/lifecycle/core-lifecycle-server-mocks/src/core_setup.mock.ts @@ -48,6 +48,7 @@ export function createCoreSetupMock({ const uiSettingsMock = { register: uiSettingsServiceMock.createSetupContract().register, registerGlobal: uiSettingsServiceMock.createSetupContract().registerGlobal, + setAllowlist: uiSettingsServiceMock.createSetupContract().setAllowlist, }; const mock: CoreSetupMockType = { diff --git a/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts b/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts index 5ca77254e5b50..b97eea8f827ed 100644 --- a/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts @@ -258,6 +258,7 @@ export function createPluginSetupContext( uiSettings: { register: deps.uiSettings.register, registerGlobal: deps.uiSettings.registerGlobal, + setAllowlist: deps.uiSettings.setAllowlist, }, userSettings: { setUserProfileSettings: deps.userSettings.setUserProfileSettings, diff --git a/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_client_common.ts b/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_client_common.ts index ac74201e0f307..65a3c44861ed5 100644 --- a/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_client_common.ts +++ b/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_client_common.ts @@ -116,6 +116,10 @@ You can use \`IUiSettingsClient.get("${key}", defaultValue)\`, which will just r return this.isDeclared(key) && Boolean(this.cache[key].isOverridden); } + isStrictReadonly(key: string) { + return this.isDeclared(key) && Boolean(this.cache[key].readonlyMode === 'strict'); + } + getUpdate$() { return this.update$.asObservable(); } @@ -130,6 +134,9 @@ You can use \`IUiSettingsClient.get("${key}", defaultValue)\`, which will just r `Unable to update "${key}" because its value is overridden by the Kibana server` ); } + if (this.isStrictReadonly(key)) { + throw new Error(`Unable to update "${key}" because this setting is not in the allowlist.`); + } } protected abstract update(key: string, newVal: any): Promise; diff --git a/packages/core/ui-settings/core-ui-settings-common/index.ts b/packages/core/ui-settings/core-ui-settings-common/index.ts index f04a41613f76f..02604e122a2ae 100644 --- a/packages/core/ui-settings/core-ui-settings-common/index.ts +++ b/packages/core/ui-settings/core-ui-settings-common/index.ts @@ -8,6 +8,7 @@ export type { UiSettingsType, + ReadonlyModeType, DeprecationSettings, UiSettingsParams, UserProvidedValues, diff --git a/packages/core/ui-settings/core-ui-settings-common/src/ui_settings.ts b/packages/core/ui-settings/core-ui-settings-common/src/ui_settings.ts index 9a4cf094433d4..2655eda8b94b9 100644 --- a/packages/core/ui-settings/core-ui-settings-common/src/ui_settings.ts +++ b/packages/core/ui-settings/core-ui-settings-common/src/ui_settings.ts @@ -25,6 +25,14 @@ export type UiSettingsType = | 'image' | 'color'; +/** + * Type for the readonly mode of the readonly settings. + * 'strict' indicates that the value cannot be changed through API and is not displayed in the UI + * 'ui' indicates that the value is just not displayed in the UI + * @public + * */ +export type ReadonlyModeType = 'strict' | 'ui'; + /** * UiSettings deprecation field options. * @public @@ -57,6 +65,8 @@ export interface UiSettingsParams { requiresPageReload?: boolean; /** a flag indicating that value cannot be changed */ readonly?: boolean; + /** a flag indicating the level of restriction of the readonly settings {@link ReadonlyModeType} */ + readonlyMode?: ReadonlyModeType; /** * a flag indicating that value might contain user sensitive data. * used by telemetry to mask the value of the setting when sent. diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.test.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.test.ts index 23438e2ab74af..72450e86eadb1 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.test.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.test.ts @@ -112,6 +112,18 @@ describe('uiSettings', () => { expect(() => setup.registerGlobal(defaults)).not.toThrow(); }); }); + + describe('#setAllowlist', () => { + // Skipped because we disabled this multi-call check temporarily + it.skip('throws if setAllowlist is called twice', async () => { + const { setAllowlist } = await service.setup(setupDeps); + setAllowlist(['mySetting']); + + expect(() => setAllowlist(['newSetting'])).toThrowErrorMatchingInlineSnapshot( + `"The uiSettings allowlist has already been set up. Instead of calling setAllowlist(), add your settings to packages/serverless/settings"` + ); + }); + }); }); describe('#start', () => { @@ -213,6 +225,59 @@ describe('uiSettings', () => { await customizedService.start(); }); + + it('throws when the allowlist contains unregistered settings', async () => { + const { setAllowlist } = await service.setup(setupDeps); + setAllowlist(['mySetting']); + + await expect(service.start()).rejects.toMatchInlineSnapshot( + `[Error: The uiSetting with key [mySetting] is in the allowlist but is not registered. Make sure to remove it from the allowlist in /packages/serverless/settings]` + ); + }); + }); + + describe('#applyAllowlist', () => { + const settingId = 'mySetting'; + const testSetting = { + name: 'My setting', + value: 10, + readonly: true, + schema: schema.number(), + }; + + it('allowlisted readonly settings have "ui" readonly mode', async () => { + const { register, setAllowlist } = await service.setup(setupDeps); + register({ [settingId]: testSetting }); + setAllowlist([settingId]); + + const expectedSetting = { + ...testSetting, + readonlyMode: 'ui', + }; + + const start = await service.start(); + start.asScopedToClient(savedObjectsClient); + expect(MockUiSettingsClientConstructor.mock.calls[0][0].defaults).toEqual({ + [settingId]: expectedSetting, + }); + }); + + it('non-allowlisted settings have "strict" readonly mode', async () => { + const { register, setAllowlist } = await service.setup(setupDeps); + register({ [settingId]: testSetting }); + setAllowlist([]); + + const expectedSetting = { + ...testSetting, + readonlyMode: 'strict', + }; + + const start = await service.start(); + start.asScopedToClient(savedObjectsClient); + expect(MockUiSettingsClientConstructor.mock.calls[0][0].defaults).toEqual({ + [settingId]: expectedSetting, + }); + }); }); describe('#asScopedToClient', () => { diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.ts index 3352ab0ab63b0..63b3ef7f66262 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.ts @@ -15,7 +15,11 @@ import type { CoreContext, CoreService } from '@kbn/core-base-server-internal'; import type { InternalHttpServiceSetup } from '@kbn/core-http-server-internal'; import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import type { InternalSavedObjectsServiceSetup } from '@kbn/core-saved-objects-server-internal'; -import type { UiSettingsParams, UiSettingsScope } from '@kbn/core-ui-settings-common'; +import type { + ReadonlyModeType, + UiSettingsParams, + UiSettingsScope, +} from '@kbn/core-ui-settings-common'; import { UiSettingsConfigType, uiSettingsConfig as uiConfigDefinition } from './ui_settings_config'; import { UiSettingsClient, UiSettingsClientFactory, UiSettingsGlobalClient } from './clients'; import type { @@ -47,14 +51,17 @@ export class UiSettingsService private readonly log: Logger; private readonly config$: Observable; private readonly isDist: boolean; + private readonly isDev: boolean; private readonly uiSettingsDefaults = new Map(); private readonly uiSettingsGlobalDefaults = new Map(); private overrides: Record = {}; + private allowlist: Set | null = null; constructor(private readonly coreContext: CoreContext) { this.log = coreContext.logger.get('ui-settings-service'); this.isDist = coreContext.env.packageInfo.dist; this.config$ = coreContext.configService.atPath(uiConfigDefinition.path); + this.isDev = coreContext.env.mode.dev; } public async preboot(): Promise { @@ -94,10 +101,19 @@ export class UiSettingsService return { register: this.register, registerGlobal: this.registerGlobal, + setAllowlist: this.setAllowlist, }; } public async start(): Promise { + if (this.allowlist) { + // If we are in development mode, check if all settings in the allowlist are registered + if (this.isDev) { + this.validateAllowlist(); + } + this.applyAllowlist(this.uiSettingsDefaults, false); + this.applyAllowlist(this.uiSettingsGlobalDefaults, true); + } this.validatesDefinitions(); this.validatesOverrides(); @@ -148,6 +164,55 @@ export class UiSettingsService }); }; + private setAllowlist = (keys: string[]) => { + // Disabling this check for now since it causes some test failures + // if (this.allowlist) { + // throw new Error( + // `The uiSettings allowlist has already been set up. Instead of calling setAllowlist(), add your settings to packages/serverless/settings` + // ); + // } + this.allowlist = new Set(keys); + }; + + private validateAllowlist() { + this.allowlist?.forEach((key) => { + if (!this.uiSettingsDefaults.has(key) && !this.uiSettingsGlobalDefaults.has(key)) { + throw new Error( + `The uiSetting with key [${key}] is in the allowlist but is not registered. Make sure to remove it from the allowlist in /packages/serverless/settings` + ); + } + }); + } + + private setReadonlyMode(key: string, mode: ReadonlyModeType, isGlobal: boolean) { + if (isGlobal) { + const definition = this.uiSettingsGlobalDefaults.get(key); + if (definition) { + this.uiSettingsGlobalDefaults.set(key, { ...definition, readonlyMode: mode }); + } + } else { + const definition = this.uiSettingsDefaults.get(key); + if (definition) { + this.uiSettingsDefaults.set(key, { ...definition, readonlyMode: mode }); + } + } + } + + private applyAllowlist(settingsDefaults: Map, isGlobal: boolean) { + for (const [key, definition] of settingsDefaults) { + // Settings in the allowlist that are already read-only should have 'ui' readonly mode + if (this.allowlist?.has(key) && definition.readonly === true) { + this.setReadonlyMode(key, 'ui', isGlobal); + } + + // Setting that are not in the allowlist should have 'strict' readonly mode + if (!this.allowlist?.has(key)) { + definition.readonly = true; + this.setReadonlyMode(key, 'strict', isGlobal); + } + } + } + private validatesDefinitions() { for (const [key, definition] of this.uiSettingsDefaults) { if (!definition.schema) { diff --git a/packages/core/ui-settings/core-ui-settings-server-mocks/src/ui_settings_service.mock.ts b/packages/core/ui-settings/core-ui-settings-server-mocks/src/ui_settings_service.mock.ts index 5d4b4c62ebb1e..280d75319a8bf 100644 --- a/packages/core/ui-settings/core-ui-settings-server-mocks/src/ui_settings_service.mock.ts +++ b/packages/core/ui-settings/core-ui-settings-server-mocks/src/ui_settings_service.mock.ts @@ -49,6 +49,7 @@ const createSetupMock = () => { const mocked: jest.Mocked = { register: jest.fn(), registerGlobal: jest.fn(), + setAllowlist: jest.fn(), }; return mocked; diff --git a/packages/core/ui-settings/core-ui-settings-server/src/contracts.ts b/packages/core/ui-settings/core-ui-settings-server/src/contracts.ts index 18d25a9031b24..65bae4100e4ad 100644 --- a/packages/core/ui-settings/core-ui-settings-server/src/contracts.ts +++ b/packages/core/ui-settings/core-ui-settings-server/src/contracts.ts @@ -48,6 +48,19 @@ export interface UiSettingsServiceSetup { * ``` */ registerGlobal(settings: Record): void; + + /** + * Sets an allowlist of setting keys. + * @param keys + * + * @example + * ```ts + * setup(core: CoreSetup){ + * core.uiSettings.setAllowlist(['csv:quoteValues', 'dateFormat:dow']); + * } + * ``` + */ + setAllowlist(keys: string[]): void; } /** @public */ diff --git a/packages/kbn-management/settings/setting_ids/README.mdx b/packages/kbn-management/settings/setting_ids/README.mdx new file mode 100644 index 0000000000000..e3109e2bcf1b5 --- /dev/null +++ b/packages/kbn-management/settings/setting_ids/README.mdx @@ -0,0 +1,39 @@ +--- +id: kbn-management/settings/ids +slug: /kbn-management/settings/setting_ids/ +title: Setting ID's +description: ID's of all advanced settings. +tags: ['management', 'settings'] +date: 2023-09-04 +--- + +This package contains the id's of all advanced settings. + +When registering an advanced setting, add its id to this package and import it for use in the setting definition: + +**packages/kbn-management/settings/setting_ids/index.ts** + +```ts +export const MY_SETTING_ID = 'mySetting'; +``` + +**src/plugins/my_plugin/server/plugin.ts** + +```ts +import { MY_SETTING_ID } from '@kbn/management-settings-ids'; + +export class MyPlugin implements Plugin { + public setup(core: CoreSetup, dependencies: SetupDependencies) { + core.uiSettings.register({ + [MY_SETTING_ID]: { + name: 'My setting', + value: 10, + schema: schema.number(), + }, + ... + }); + + return {}; + } +} +``` diff --git a/packages/kbn-management/settings/setting_ids/index.ts b/packages/kbn-management/settings/setting_ids/index.ts new file mode 100644 index 0000000000000..1069050ccd304 --- /dev/null +++ b/packages/kbn-management/settings/setting_ids/index.ts @@ -0,0 +1,178 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +// General settings +export const DISABLE_REQUEST_BATCHING_ID = 'bfetch:disable'; +export const DISABLE_BATCH_COMPRESSION_ID = 'bfetch:disableCompression'; +export const CSV_QUOTE_VALUES_ID = 'csv:quoteValues'; +export const CSV_SEPARATOR_ID = 'csv:separator'; +export const DATE_FORMAT_ID = 'dateFormat'; +export const DATE_FORMAT_DOW_ID = 'dateFormat:dow'; +export const DATE_FORMAT_SCALED_ID = 'dateFormat:scaled'; +export const DATE_FORMAT_TZ_ID = 'dateFormat:tz'; +export const DATE_FORMAT_NANOS_ID = 'dateNanosFormat'; +export const DEFAULT_INDEX_ID = 'defaultIndex'; +export const DEFAULT_ROUTE_ID = 'defaultRoute'; +export const FIELDS_POPULAR_LIMIT_ID = 'fields:popularLimit'; +export const FILE_UPLOAD_MAX_SIZE_ID = 'fileUpload:maxFileSize'; +export const FILTER_EDITOR_SUGGEST_VALUES_ID = 'filterEditor:suggestValues'; +export const FILTERS_PINNED_BY_DEFAULT_ID = 'filters:pinnedByDefault'; +export const FORMAT_BYTES_DEFAULT_PATTERN_ID = 'format:bytes:defaultPattern'; +export const FORMAT_CURRENCY_DEFAULT_PATTERN_ID = 'format:currency:defaultPattern'; +export const FORMAT_DEFAULT_TYPE_MAP_ID = 'format:defaultTypeMap'; +export const FORMAT_NUMBER_DEFAULT_LOCALE_ID = 'format:number:defaultLocale'; +export const FORMAT_NUMBER_DEFAULT_PATTERN_ID = 'format:number:defaultPattern'; +export const FORMAT_PERCENT_DEFAULT_PATTERN_ID = 'format:percent:defaultPattern'; +export const HIDE_ANNOUNCEMENTS_ID = 'hideAnnouncements'; +export const HISTOGRAM_BAR_TARGET_ID = 'histogram:barTarget'; +export const HISTOGRAM_MAX_BARS_ID = 'histogram:maxBars'; +export const HISTORY_LIMIT_ID = 'history:limit'; +export const META_FIELDS_ID = 'metaFields'; +export const METRICS_ALLOW_CHECKING_FOR_FAILED_SHARDS_ID = 'metrics:allowCheckingForFailedShards'; +export const METRICS_ALLOW_STRING_INDICES_ID = 'metrics:allowStringIndices'; +export const METRICS_MAX_BUCKETS_ID = 'metrics:max_buckets'; +export const QUERY_ALLOW_LEADING_WILDCARDS_ID = 'query:allowLeadingWildcards'; +export const QUERY_STRING_OPTIONS_ID = 'query:queryString:options'; +export const SAVED_OBJECTS_LISTING_LIMIT_ID = 'savedObjects:listingLimit'; +export const SAVED_OBJECTS_PER_PAGE_ID = 'savedObjects:perPage'; +export const SEARCH_QUERY_LANGUAGE_ID = 'search:queryLanguage'; +export const SHORT_DOTS_ENABLE_ID = 'shortDots:enable'; +export const SORT_OPTIONS_ID = 'sort:options'; +export const STATE_STORE_IN_SESSION_STORAGE_ID = 'state:storeInSessionStorage'; +export const THEME_DARK_MODE_ID = 'theme:darkMode'; +export const TIMEPICKER_QUICK_RANGES_ID = 'timepicker:quickRanges'; +export const TIMEPICKER_REFRESH_INTERVAL_DEFAULTS_ID = 'timepicker:refreshIntervalDefaults'; +export const TIMEPICKER_TIME_DEFAULTS_ID = 'timepicker:timeDefaults'; + +// Presentation labs settings +export const LABS_CANVAS_BY_VALUE_EMBEDDABLE_ID = 'labs:canvas:byValueEmbeddable'; +export const LABS_CANVAS_ENABLE_UI_ID = 'labs:canvas:enable_ui'; +export const LABS_DASHBOARD_CONTROLS_ID = 'labs:dashboard:dashboardControls'; +export const LABS_DASHBOARD_DEFER_BELOW_FOLD_ID = 'labs:dashboard:deferBelowFold'; +export const LABS_DASHBOARDS_ENABLE_UI_ID = 'labs:dashboard:enable_ui'; + +// Accessibility settings +export const ACCESSIBILITY_DISABLE_ANIMATIONS_ID = 'accessibility:disableAnimations'; + +// Autocomplete settings +export const AUTOCOMPLETE_USE_TIME_RANGE_ID = 'autocomplete:useTimeRange'; +export const AUTOCOMPLETE_VALUE_SUGGESTION_METHOD_ID = 'autocomplete:valueSuggestionMethod'; + +// Banner settings +export const BANNERS_PLACEMENT_ID = 'banners:placement'; +export const BANNERS_TEXT_CONTENT_ID = 'banners:textContent'; +export const BANNERS_TEXT_COLOR_ID = 'banners:textColor'; +export const BANNERS_BACKGROUND_COLOR_ID = 'banners:backgroundColor'; + +// Discover settings +export const CONTEXT_DEFAULT_SIZE_ID = 'context:defaultSize'; +export const CONTEXT_STEP_ID = 'context:step'; +export const CONTEXT_TIE_BREAKER_FIELDS_ID = 'context:tieBreakerFields'; +export const DEFAULT_COLUMNS_ID = 'defaultColumns'; +export const DISCOVER_ENABLE_SQL_ID = 'discover:enableSql'; +export const DISCOVER_MAX_DOC_FIELDS_DISPLAYED_ID = 'discover:maxDocFieldsDisplayed'; +export const DISCOVER_MODIFY_COLUMNS_ON_SWITCH_ID = 'discover:modifyColumnsOnSwitch'; +export const DISCOVER_ROW_HEIGHT_OPTION_ID = 'discover:rowHeightOption'; +export const DISCOVER_SAMPLE_ROWS_PER_PAGE_ID = 'discover:sampleRowsPerPage'; +export const DISCOVER_SAMPLE_SIZE_ID = 'discover:sampleSize'; +export const DISCOVER_SEARCH_FIELDS_FROM_SOURCE_ID = 'discover:searchFieldsFromSource'; +export const DISCOVER_SEARCH_ON_PAGE_LOAD_ID = 'discover:searchOnPageLoad'; +export const DISCOVER_SHOW_FIELD_STATISTICS_ID = 'discover:showFieldStatistics'; +export const DISCOVER_SHOW_LEGACY_FIELD_TOP_VALUES_ID = 'discover:showLegacyFieldTopValues'; +export const DISCOVER_SHOW_MULTI_FIELDS_ID = 'discover:showMultiFields'; +export const DISCOVER_SORT_DEFAULT_ORDER_ID = 'discover:sort:defaultOrder'; +export const DOC_TABLE_HIDE_TIME_COLUMNS_ID = 'doc_table:hideTimeColumn'; +export const DOC_TABLE_HIGHLIGHT_ID = 'doc_table:highlight'; +export const DOC_TABLE_LEGACY_ID = 'doc_table:legacy'; +export const TRUNCATE_MAX_HEIGHT_ID = 'truncate:maxHeight'; + +// Machine learning settings +export const ML_ANOMALY_DETECTION_RESULTS_ENABLE_TIME_DEFAULTS_ID = + 'ml:anomalyDetection:results:enableTimeDefaults'; +export const ML_ANOMALY_DETECTION_RESULTS_TIME_DEFAULTS_ID = + 'ml:anomalyDetection:results:timeDefaults'; + +// Notifications settings +export const NOTIFICATIONS_BANNER_ID = 'notifications:banner'; +export const NOTIFICATIONS_LIFETIME_BANNER_ID = 'notifications:lifetime:banner'; +export const NOTIFICATIONS_LIFETIME_ERROR_ID = 'notifications:lifetime:error'; +export const NOTIFICATIONS_LIFETIME_INFO_ID = 'notifications:lifetime:info'; +export const NOTIFICATIONS_LIFETIME_WARNING_ID = 'notifications:lifetime:warning'; + +// Observability settings +export const OBSERVABILITY_APM_AWS_LAMBDA_PRICE_FACTOR_ID = 'observability:apmAWSLambdaPriceFactor'; +export const OBSERVABILITY_APM_AWS_LAMBDA_REQUEST_COST_PER_MILLION_ID = + 'observability:apmAWSLambdaRequestCostPerMillion'; +export const OBSERVABILITY_APM_AGENT_EXPLORER_VIEW_ID = 'observability:apmAgentExplorerView'; +export const OBSERVABILITY_APM_DEFAULT_SERVICE_ENVIRONMENT_ID = + 'observability:apmDefaultServiceEnvironment'; +export const OBSERVABILITY_APM_ENABLE_CRITICAL_PATH_ID = 'observability:apmEnableCriticalPath'; +export const OBSERVABILITY_APM_LABS_BUTTON_ID = 'observability:apmLabsButton'; +export const OBSERVABILITY_APM_PROGRESSIVE_LOADING_ID = 'observability:apmProgressiveLoading'; +export const OBSERVABILITY_APM_SERVICE_GROUP_MAX_NUMBER_OF_SERVCIE_ID = + 'observability:apmServiceGroupMaxNumberOfServices'; +export const OBSERVABILITY_APM_SERVICE_INVENTORY_OPTIMIZED_SORTING_ID = + 'observability:apmServiceInventoryOptimizedSorting'; +export const OBSERVABILITY_APM_TRACE_EXPLORER_TAB_ID = 'observability:apmTraceExplorerTab'; +export const OBSERVABILITY_ENABLE_AWS_LAMBDA_METRICS_ID = 'observability:enableAwsLambdaMetrics'; +export const OBSERVABILITY_ENABLE_COMPARISON_BY_DEFAULT_ID = + 'observability:enableComparisonByDefault'; +export const OBSERVABILITY_ENABLE_INFRASTRUCTURE_HOSTS_VIEW_ID = + 'observability:enableInfrastructureHostsView'; +export const OBSERVABILITY_ENABLE_INSPECT_ES_QUERIES_ID = 'observability:enableInspectEsQueries'; +export const OBSERVABILITY_MAX_SUGGESTIONS_ID = 'observability:maxSuggestions'; +export const OBSERVABILITY_PROFILING_ELASTICSEARCH_PLUGIN_ID = + 'observability:profilingElasticsearchPlugin'; + +// Reporting settings +export const XPACK_REPORTING_CUSTOM_PDF_LOGO_ID = 'xpackReporting:customPdfLogo'; + +// Rollups settings +export const ROLLUPS_ENABLE_INDEX_PATTERNS_ID = 'rollups.enableIndexPatterns'; + +// Search settings +export const COURIER_CUSTOM_REQUEST_PREFERENCE_ID = 'courier:customRequestPreference'; +export const COURIER_IGNORE_FILTER_IF_FIELD_NOT_IN_INDEX_ID = + 'courier:ignoreFilterIfFieldNotInIndex'; +export const COURIER_MAX_CONCURRENT_SHARD_REQUEST_ID = 'courier:maxConcurrentShardRequests'; +export const COURIER_SET_REQUEST_PREFERENCE_ID = 'courier:setRequestPreference'; +export const SEARCH_INCLUDE_FROZEN_ID = 'search:includeFrozen'; +export const SEARCH_TIMEOUT_ID = 'search:timeout'; + +// Security solution settings +export const SECURITY_SOLUTION_REFRESH_INTERVAL_DEFAULTS_ID = + 'securitySolution:refreshIntervalDefaults'; +export const SECURITY_SOLUTION_TIME_DEFAULTS_ID = 'securitySolution:timeDefaults'; +export const SECURITY_SOLUTION_DEFAULT_INDEX_ID = 'securitySolution:defaultIndex'; +export const SECURITY_SOLUTION_DEFAULT_THREAT_INDEX_ID = 'securitySolution:defaultThreatIndex'; +export const SECURITY_SOLUTION_DEFAULT_ANOMALY_SCORE_ID = 'securitySolution:defaultAnomalyScore'; +export const SECURITY_SOLUTION_ENABLE_GROUPED_NAV_ID = 'securitySolution:enableGroupedNav'; +export const SECURITY_SOLUTION_ENABLE_NEWS_FEED_ID = 'securitySolution:enableNewsFeed'; +export const SECURITY_SOLUTION_RULES_TABLE_REFRESH_ID = 'securitySolution:rulesTableRefresh'; +export const SECURITY_SOLUTION_NEWS_FEED_URL_ID = 'securitySolution:newsFeedUrl'; +export const SECURITY_SOLUTION_IP_REPUTATION_LINKS_ID = 'securitySolution:ipReputationLinks'; +export const SECURITY_SOLUTION_ENABLE_CCS_WARNING_ID = 'securitySolution:enableCcsWarning'; +export const SECURITY_SOLUTION_SHOW_RELATED_INTEGRATIONS_ID = + 'securitySolution:showRelatedIntegrations'; + +// Timelion settings +export const TIMELION_ES_DEFAULT_INDEX_ID = 'timelion:es.default_index'; +export const TIMELION_ES_TIME_FIELD_ID = 'timelion:es.timefield'; +export const TIMELION_MAX_BUCKETS_ID = 'timelion:max_buckets'; +export const TIMELION_MIN_INTERVAL_ID = 'timelion:min_interval'; +export const TIMELION_TARGET_BUCKETS_ID = 'timelion:target_buckets'; + +// Visualization settings +export const VISUALIZATION_COLOR_MAPPING_ID = 'visualization:colorMapping'; +export const VISUALIZATION_HEATMAP_MAX_BUCKETS_ID = 'visualization:heatmap:maxBuckets'; +export const VISUALIZATION_USE_LEGACY_TIME_AXIS_ID = 'visualization:useLegacyTimeAxis'; +export const VISUALIZATION_LEGACY_GAUGE_CHARTS_LIBRARY_ID = + 'visualization:visualize:legacyGaugeChartsLibrary'; +export const VISUALIZATION_LEGACY_HEATMAP_CHARTS_LIBRARY_ID = + 'visualization:visualize:legacyHeatmapChartsLibrary'; +export const VISUALIZATION_ENABLE_LABS_ID = 'visualize:enableLabs'; diff --git a/packages/kbn-management/settings/setting_ids/kibana.jsonc b/packages/kbn-management/settings/setting_ids/kibana.jsonc new file mode 100644 index 0000000000000..934b0dd5baaac --- /dev/null +++ b/packages/kbn-management/settings/setting_ids/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/management-settings-ids", + "owner": "@elastic/appex-sharedux @elastic/platform-deployment-management" +} diff --git a/packages/kbn-management/settings/setting_ids/package.json b/packages/kbn-management/settings/setting_ids/package.json new file mode 100644 index 0000000000000..59c9769cd1bf7 --- /dev/null +++ b/packages/kbn-management/settings/setting_ids/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/management-settings-ids", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/kbn-management/settings/setting_ids/tsconfig.json b/packages/kbn-management/settings/setting_ids/tsconfig.json new file mode 100644 index 0000000000000..53e5c76cbab87 --- /dev/null +++ b/packages/kbn-management/settings/setting_ids/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], +} diff --git a/packages/serverless/settings/common/README.mdx b/packages/serverless/settings/common/README.mdx new file mode 100644 index 0000000000000..ece99219fbc3b --- /dev/null +++ b/packages/serverless/settings/common/README.mdx @@ -0,0 +1,14 @@ +--- +id: serverless/packages/settings/common +slug: /serverless/packages/settings/common +title: Serverless Common Advanced Settings +description: A package of common settings for all Serverless projects. +tags: ['serverless', 'package'] +date: 2023-08-24 +--- + +This package contains a list of UI settings that are available in all Serverless projects in the Advanced settings app. +This list is consumed by the `serverless` plugin, which merges it with any serverless project-specific settings that +have been set up, and sends it to the uiSettings service to set an allowlist for the settings. + +If you need to register a setting that should be available in all serverless projects, make sure to add its Id to this list. diff --git a/packages/serverless/settings/common/index.ts b/packages/serverless/settings/common/index.ts new file mode 100644 index 0000000000000..326108abcd747 --- /dev/null +++ b/packages/serverless/settings/common/index.ts @@ -0,0 +1,58 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import * as settings from '@kbn/management-settings-ids'; + +const GENERAL_SETTINGS = [ + settings.CSV_QUOTE_VALUES_ID, + settings.DATE_FORMAT_DOW_ID, + settings.DATE_FORMAT_SCALED_ID, + settings.DATE_FORMAT_TZ_ID, + settings.DATE_FORMAT_NANOS_ID, + settings.DEFAULT_INDEX_ID, + settings.FILTERS_PINNED_BY_DEFAULT_ID, + settings.FORMAT_BYTES_DEFAULT_PATTERN_ID, + settings.FORMAT_CURRENCY_DEFAULT_PATTERN_ID, + settings.FORMAT_NUMBER_DEFAULT_LOCALE_ID, + settings.FORMAT_NUMBER_DEFAULT_PATTERN_ID, + settings.FORMAT_PERCENT_DEFAULT_PATTERN_ID, + settings.META_FIELDS_ID, + settings.STATE_STORE_IN_SESSION_STORAGE_ID, + settings.TIMEPICKER_QUICK_RANGES_ID, + settings.TIMEPICKER_TIME_DEFAULTS_ID, +]; + +const PRESENTATION_LABS_SETTINGS = [settings.LABS_DASHBOARD_DEFER_BELOW_FOLD_ID]; + +const ACCESSIBILITY_SETTINGS = [settings.ACCESSIBILITY_DISABLE_ANIMATIONS_ID]; + +const BANNER_SETTINGS = [ + settings.BANNERS_PLACEMENT_ID, + settings.BANNERS_TEXT_CONTENT_ID, + settings.BANNERS_TEXT_COLOR_ID, + settings.BANNERS_BACKGROUND_COLOR_ID, +]; + +const DISCOVER_SETTINGS = [settings.DEFAULT_COLUMNS_ID]; + +const NOTIFICATION_SETTINGS = [ + settings.NOTIFICATIONS_BANNER_ID, + settings.NOTIFICATIONS_LIFETIME_BANNER_ID, + settings.NOTIFICATIONS_LIFETIME_ERROR_ID, + settings.NOTIFICATIONS_LIFETIME_INFO_ID, + settings.NOTIFICATIONS_LIFETIME_WARNING_ID, +]; + +export const ALL_COMMON_SETTINGS = [ + ...GENERAL_SETTINGS, + ...PRESENTATION_LABS_SETTINGS, + ...ACCESSIBILITY_SETTINGS, + ...BANNER_SETTINGS, + ...DISCOVER_SETTINGS, + ...NOTIFICATION_SETTINGS, +]; diff --git a/packages/serverless/settings/common/kibana.jsonc b/packages/serverless/settings/common/kibana.jsonc new file mode 100644 index 0000000000000..ee4ea591c85c5 --- /dev/null +++ b/packages/serverless/settings/common/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/serverless-common-settings", + "owner": "@elastic/appex-sharedux @elastic/platform-deployment-management" +} diff --git a/packages/serverless/settings/common/package.json b/packages/serverless/settings/common/package.json new file mode 100644 index 0000000000000..3674091a63be5 --- /dev/null +++ b/packages/serverless/settings/common/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/serverless-common-settings", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/serverless/settings/common/tsconfig.json b/packages/serverless/settings/common/tsconfig.json new file mode 100644 index 0000000000000..16d6022e3d9bc --- /dev/null +++ b/packages/serverless/settings/common/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/management-settings-ids", + ] +} diff --git a/packages/serverless/settings/observability_project/README.mdx b/packages/serverless/settings/observability_project/README.mdx new file mode 100644 index 0000000000000..e7c16971c6cb6 --- /dev/null +++ b/packages/serverless/settings/observability_project/README.mdx @@ -0,0 +1,31 @@ +--- +id: serverless/packages/settings/observability_project +slug: /serverless/packages/settings/observability_project +title: Serverless Observability Advanced Settings +description: A package of settings for the Serverless Observability project. +tags: ['serverless', 'package'] +date: 2023-08-24 +--- + +This package contains a list of UI settings that are only available in the Serverless Observability project. +This list is consumed by the `serverless_observability` plugin, which sets up its project settings: + +```ts +export class ServerlessObservabilityPlugin + implements + Plugin< + ServerlessObservabilityPluginSetup, + ServerlessObservabilityPluginStart, + SetupDependencies, + StartDependencies + > +{ + public setup(_coreSetup: CoreSetup, pluginsSetup: SetupDependencies) { + pluginsSetup.serverless.setupProjectSettings(OBSERVABILITY_PROJECT_SETTINGS); + return {}; + } +} +``` + +If you need to register a setting that should be available in the Serverless Observability project, make sure to add +its Id to this list. diff --git a/packages/serverless/settings/observability_project/index.ts b/packages/serverless/settings/observability_project/index.ts new file mode 100644 index 0000000000000..7f76a35e0fcea --- /dev/null +++ b/packages/serverless/settings/observability_project/index.ts @@ -0,0 +1,14 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import * as settings from '@kbn/management-settings-ids'; + +export const OBSERVABILITY_PROJECT_SETTINGS = [ + settings.ML_ANOMALY_DETECTION_RESULTS_ENABLE_TIME_DEFAULTS_ID, + settings.ML_ANOMALY_DETECTION_RESULTS_TIME_DEFAULTS_ID, +]; diff --git a/packages/serverless/settings/observability_project/kibana.jsonc b/packages/serverless/settings/observability_project/kibana.jsonc new file mode 100644 index 0000000000000..4df29091e6619 --- /dev/null +++ b/packages/serverless/settings/observability_project/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/serverless-observability-settings", + "owner": "@elastic/appex-sharedux @elastic/apm-ui @elastic/platform-deployment-management" +} diff --git a/packages/serverless/settings/observability_project/package.json b/packages/serverless/settings/observability_project/package.json new file mode 100644 index 0000000000000..127cb4621c742 --- /dev/null +++ b/packages/serverless/settings/observability_project/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/serverless-observability-settings", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/serverless/settings/observability_project/tsconfig.json b/packages/serverless/settings/observability_project/tsconfig.json new file mode 100644 index 0000000000000..16d6022e3d9bc --- /dev/null +++ b/packages/serverless/settings/observability_project/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/management-settings-ids", + ] +} diff --git a/packages/serverless/settings/search_project/README.mdx b/packages/serverless/settings/search_project/README.mdx new file mode 100644 index 0000000000000..a19718c645a82 --- /dev/null +++ b/packages/serverless/settings/search_project/README.mdx @@ -0,0 +1,34 @@ +--- +id: serverless/packages/settings/search_project +slug: /serverless/packages/settings/search_project +title: Serverless Search Advanced Settings +description: A package of settings for the Serverless Search project. +tags: ['serverless', 'package'] +date: 2023-08-24 +--- + +This package contains a list of UI settings that are only available in the Serverless Search project. +This list is consumed by the `serverless_search` plugin, which sets up its project settings: + +```ts +export class ServerlessSearchPlugin + implements + Plugin< + ServerlessSearchPluginSetup, + ServerlessSearchPluginStart, + SetupDependencies, + StartDependencies + > +{ + public setup( + { getStartServices, http }: CoreSetup, + pluginsSetup: SetupDependencies + ) { + pluginsSetup.serverless.setupProjectSettings(SEARCH_PROJECT_SETTINGS); + return {}; + } +} +``` + +If you need to register a setting that should be available in the Serverless Search project, make sure to add +its Id to this list. diff --git a/packages/serverless/settings/search_project/index.ts b/packages/serverless/settings/search_project/index.ts new file mode 100644 index 0000000000000..a26c658501617 --- /dev/null +++ b/packages/serverless/settings/search_project/index.ts @@ -0,0 +1,11 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { COURIER_IGNORE_FILTER_IF_FIELD_NOT_IN_INDEX_ID } from '@kbn/management-settings-ids'; + +export const SEARCH_PROJECT_SETTINGS = [COURIER_IGNORE_FILTER_IF_FIELD_NOT_IN_INDEX_ID]; diff --git a/packages/serverless/settings/search_project/kibana.jsonc b/packages/serverless/settings/search_project/kibana.jsonc new file mode 100644 index 0000000000000..f73b63503ae4d --- /dev/null +++ b/packages/serverless/settings/search_project/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/serverless-search-settings", + "owner": "@elastic/enterprise-search-frontend @elastic/platform-deployment-management" +} diff --git a/packages/serverless/settings/search_project/package.json b/packages/serverless/settings/search_project/package.json new file mode 100644 index 0000000000000..2dc7bf717e612 --- /dev/null +++ b/packages/serverless/settings/search_project/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/serverless-search-settings", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/serverless/settings/search_project/tsconfig.json b/packages/serverless/settings/search_project/tsconfig.json new file mode 100644 index 0000000000000..16d6022e3d9bc --- /dev/null +++ b/packages/serverless/settings/search_project/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/management-settings-ids", + ] +} diff --git a/packages/serverless/settings/security_project/README.mdx b/packages/serverless/settings/security_project/README.mdx new file mode 100644 index 0000000000000..4d5d788eb84d0 --- /dev/null +++ b/packages/serverless/settings/security_project/README.mdx @@ -0,0 +1,31 @@ +--- +id: serverless/packages/settings/security_project +slug: /serverless/packages/settings/security_project +title: Serverless Security Advanced Settings +description: A package of settings for the Serverless Security project. +tags: ['serverless', 'package'] +date: 2023-08-24 +--- + +This package contains a list of UI settings that are only available in the Serverless Security project. +This list is consumed by the `security_solution_serverless` plugin, which sets up its project settings: + +```ts +export class SecuritySolutionServerlessPlugin + implements + Plugin< + SecuritySolutionServerlessPluginSetup, + SecuritySolutionServerlessPluginStart, + SecuritySolutionServerlessPluginSetupDeps, + SecuritySolutionServerlessPluginStartDeps + > +{ + public setup(coreSetup: CoreSetup, pluginsSetup: SecuritySolutionServerlessPluginSetupDeps) { + pluginsSetup.serverless.setupProjectSettings(SECURITY_PROJECT_SETTINGS); + return {}; + } +} +``` + +If you need to register a setting that should be available in the Serverless Security project, make sure to add +its Id to this list. diff --git a/packages/serverless/settings/security_project/index.ts b/packages/serverless/settings/security_project/index.ts new file mode 100644 index 0000000000000..070a75f163d41 --- /dev/null +++ b/packages/serverless/settings/security_project/index.ts @@ -0,0 +1,23 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import * as settings from '@kbn/management-settings-ids'; + +export const SECURITY_PROJECT_SETTINGS = [ + settings.ML_ANOMALY_DETECTION_RESULTS_ENABLE_TIME_DEFAULTS_ID, + settings.ML_ANOMALY_DETECTION_RESULTS_TIME_DEFAULTS_ID, + settings.SECURITY_SOLUTION_REFRESH_INTERVAL_DEFAULTS_ID, + settings.SECURITY_SOLUTION_TIME_DEFAULTS_ID, + settings.SECURITY_SOLUTION_DEFAULT_INDEX_ID, + settings.SECURITY_SOLUTION_DEFAULT_THREAT_INDEX_ID, + settings.SECURITY_SOLUTION_DEFAULT_ANOMALY_SCORE_ID, + settings.SECURITY_SOLUTION_RULES_TABLE_REFRESH_ID, + settings.SECURITY_SOLUTION_IP_REPUTATION_LINKS_ID, + settings.SECURITY_SOLUTION_ENABLE_CCS_WARNING_ID, + settings.SECURITY_SOLUTION_SHOW_RELATED_INTEGRATIONS_ID, +]; diff --git a/packages/serverless/settings/security_project/kibana.jsonc b/packages/serverless/settings/security_project/kibana.jsonc new file mode 100644 index 0000000000000..818e3068d704c --- /dev/null +++ b/packages/serverless/settings/security_project/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/serverless-security-settings", + "owner": "@elastic/security-solution @elastic/platform-deployment-management" +} diff --git a/packages/serverless/settings/security_project/package.json b/packages/serverless/settings/security_project/package.json new file mode 100644 index 0000000000000..5d58ccbd142b2 --- /dev/null +++ b/packages/serverless/settings/security_project/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/serverless-security-settings", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/serverless/settings/security_project/tsconfig.json b/packages/serverless/settings/security_project/tsconfig.json new file mode 100644 index 0000000000000..16d6022e3d9bc --- /dev/null +++ b/packages/serverless/settings/security_project/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/management-settings-ids", + ] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index e5808369793ae..1459ef0fc229e 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -954,6 +954,8 @@ "@kbn/management-cards-navigation/*": ["packages/kbn-management/cards_navigation/*"], "@kbn/management-plugin": ["src/plugins/management"], "@kbn/management-plugin/*": ["src/plugins/management/*"], + "@kbn/management-settings-ids": ["packages/kbn-management/settings/setting_ids"], + "@kbn/management-settings-ids/*": ["packages/kbn-management/settings/setting_ids/*"], "@kbn/management-settings-section-registry": ["packages/kbn-management/settings/section_registry"], "@kbn/management-settings-section-registry/*": ["packages/kbn-management/settings/section_registry/*"], "@kbn/management-storybook-config": ["packages/kbn-management/storybook/config"], @@ -1260,12 +1262,20 @@ "@kbn/server-route-repository/*": ["packages/kbn-server-route-repository/*"], "@kbn/serverless": ["x-pack/plugins/serverless"], "@kbn/serverless/*": ["x-pack/plugins/serverless/*"], + "@kbn/serverless-common-settings": ["packages/serverless/settings/common"], + "@kbn/serverless-common-settings/*": ["packages/serverless/settings/common/*"], "@kbn/serverless-observability": ["x-pack/plugins/serverless_observability"], "@kbn/serverless-observability/*": ["x-pack/plugins/serverless_observability/*"], + "@kbn/serverless-observability-settings": ["packages/serverless/settings/observability_project"], + "@kbn/serverless-observability-settings/*": ["packages/serverless/settings/observability_project/*"], "@kbn/serverless-project-switcher": ["packages/serverless/project_switcher"], "@kbn/serverless-project-switcher/*": ["packages/serverless/project_switcher/*"], "@kbn/serverless-search": ["x-pack/plugins/serverless_search"], "@kbn/serverless-search/*": ["x-pack/plugins/serverless_search/*"], + "@kbn/serverless-search-settings": ["packages/serverless/settings/search_project"], + "@kbn/serverless-search-settings/*": ["packages/serverless/settings/search_project/*"], + "@kbn/serverless-security-settings": ["packages/serverless/settings/security_project"], + "@kbn/serverless-security-settings/*": ["packages/serverless/settings/security_project/*"], "@kbn/serverless-storybook-config": ["packages/serverless/storybook/config"], "@kbn/serverless-storybook-config/*": ["packages/serverless/storybook/config/*"], "@kbn/serverless-types": ["packages/serverless/types"], diff --git a/x-pack/plugins/actions/server/plugin.test.ts b/x-pack/plugins/actions/server/plugin.test.ts index d3bc3be1a9deb..dd936600d7055 100644 --- a/x-pack/plugins/actions/server/plugin.test.ts +++ b/x-pack/plugins/actions/server/plugin.test.ts @@ -15,6 +15,7 @@ import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { eventLogMock } from '@kbn/event-log-plugin/server/mocks'; +import { serverlessPluginMock } from '@kbn/serverless/server/mocks'; import { ActionType, ActionsApiRequestHandlerContext, ExecutorType } from './types'; import { ActionsConfig } from './config'; import { @@ -361,7 +362,7 @@ describe('Actions Plugin', () => { eventLog: eventLogMock.createSetup(), usageCollection: usageCollectionPluginMock.createSetupContract(), features: featuresPluginMock.createSetup(), - serverless: {}, + serverless: serverlessPluginMock.createSetupContract(), }; } @@ -560,7 +561,7 @@ describe('Actions Plugin', () => { ...pluginsSetup.encryptedSavedObjects, canEncrypt: true, }, - serverless: {}, + serverless: serverlessPluginMock.createSetupContract(), }); pluginSetup.registerType({ @@ -579,7 +580,10 @@ describe('Actions Plugin', () => { pluginSetup.setEnabledConnectorTypes(['.server-log', 'non-existing']); await expect(async () => - plugin.start(coreStart, { ...pluginsStart, serverless: {} }) + plugin.start(coreStart, { + ...pluginsStart, + serverless: serverlessPluginMock.createStartContract(), + }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Action type \\"non-existing\\" is not registered."` ); diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index ef5de6194d475..60a27eb04e411 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -40,7 +40,7 @@ import { } from '@kbn/event-log-plugin/server'; import { MonitoringCollectionSetup } from '@kbn/monitoring-collection-plugin/server'; -import { ServerlessPluginSetup } from '@kbn/serverless/server'; +import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/server'; import { ActionsConfig, AllowedHosts, EnabledConnectorTypes, getValidatedConfig } from './config'; import { resolveCustomHosts } from './lib/custom_host_settings'; import { ActionsClient } from './actions_client/actions_client'; @@ -179,7 +179,7 @@ export interface ActionsPluginsStart { eventLog: IEventLogClientService; spaces?: SpacesPluginStart; security?: SecurityPluginStart; - serverless?: ServerlessPluginSetup; + serverless?: ServerlessPluginStart; } const includedHiddenTypes = [ diff --git a/x-pack/plugins/alerting/server/plugin.test.ts b/x-pack/plugins/alerting/server/plugin.test.ts index 302bc7210c9f3..3f59d1457d57c 100644 --- a/x-pack/plugins/alerting/server/plugin.test.ts +++ b/x-pack/plugins/alerting/server/plugin.test.ts @@ -37,6 +37,7 @@ jest.mock('./alerts_service/alerts_service', () => ({ import { SharePluginStart } from '@kbn/share-plugin/server'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { generateAlertingConfig } from './test_utils'; +import { serverlessPluginMock } from '@kbn/serverless/server/mocks'; const sampleRuleType: RuleType = { id: 'test', @@ -73,8 +74,9 @@ describe('Alerting Plugin', () => { data: dataPluginMock.createSetupContract() as unknown as DataPluginSetup, features: featuresPluginMock.createSetup(), unifiedSearch: autocompletePluginMock.createSetupContract(), - // serverless setup is currently empty, and there is no mock - ...(useDataStreamForAlerts ? { serverless: {} } : {}), + ...(useDataStreamForAlerts + ? { serverless: serverlessPluginMock.createSetupContract() } + : {}), }; let plugin: AlertingPlugin; @@ -242,7 +244,9 @@ describe('Alerting Plugin', () => { data: dataPluginMock.createSetupContract() as unknown as DataPluginSetup, features: featuresPluginMock.createSetup(), unifiedSearch: autocompletePluginMock.createSetupContract(), - ...(useDataStreamForAlerts ? { serverless: {} } : {}), + ...(useDataStreamForAlerts + ? { serverless: serverlessPluginMock.createSetupContract() } + : {}), }); const startContract = plugin.start(coreMock.createStart(), { @@ -292,7 +296,9 @@ describe('Alerting Plugin', () => { data: dataPluginMock.createSetupContract() as unknown as DataPluginSetup, features: featuresPluginMock.createSetup(), unifiedSearch: autocompletePluginMock.createSetupContract(), - ...(useDataStreamForAlerts ? { serverless: {} } : {}), + ...(useDataStreamForAlerts + ? { serverless: serverlessPluginMock.createSetupContract() } + : {}), }); const startContract = plugin.start(coreMock.createStart(), { @@ -353,7 +359,9 @@ describe('Alerting Plugin', () => { data: dataPluginMock.createSetupContract() as unknown as DataPluginSetup, features: featuresPluginMock.createSetup(), unifiedSearch: autocompletePluginMock.createSetupContract(), - ...(useDataStreamForAlerts ? { serverless: {} } : {}), + ...(useDataStreamForAlerts + ? { serverless: serverlessPluginMock.createSetupContract() } + : {}), }); const startContract = plugin.start(coreMock.createStart(), { diff --git a/x-pack/plugins/event_log/server/plugin.test.ts b/x-pack/plugins/event_log/server/plugin.test.ts index 35e02459010b1..d8a51a4f0eb47 100644 --- a/x-pack/plugins/event_log/server/plugin.test.ts +++ b/x-pack/plugins/event_log/server/plugin.test.ts @@ -10,6 +10,7 @@ import { coreMock } from '@kbn/core/server/mocks'; import { IEventLogService } from '.'; import { Plugin } from './plugin'; import { spacesMock } from '@kbn/spaces-plugin/server/mocks'; +import { serverlessPluginMock } from '@kbn/serverless/server/mocks'; describe('event_log plugin', () => { it('can setup and start', () => { @@ -18,8 +19,9 @@ describe('event_log plugin', () => { const coreStart = coreMock.createStart() as CoreStart; const plugin = new Plugin(initializerContext); - // serverless setup is currently empty, and there is no mock - const setup = plugin.setup(coreSetup, { serverless: {} }); + const setup = plugin.setup(coreSetup, { + serverless: serverlessPluginMock.createSetupContract(), + }); expect(typeof setup.getLogger).toBe('function'); expect(typeof setup.getProviderActions).toBe('function'); expect(typeof setup.isIndexingEntries).toBe('function'); @@ -41,8 +43,7 @@ describe('event_log plugin', () => { const plugin = new Plugin(initializerContext); const spaces = spacesMock.createStart(); - // serverless setup is currently empty, and there is no mock - plugin.setup(coreSetup, { serverless: {} }); + plugin.setup(coreSetup, { serverless: serverlessPluginMock.createSetupContract() }); plugin.start(coreStart, { spaces }); await plugin.stop(); expect(mockLogger.debug).toBeCalledWith('shutdown: waiting to finish'); diff --git a/x-pack/plugins/security_solution_serverless/server/plugin.ts b/x-pack/plugins/security_solution_serverless/server/plugin.ts index f4937ea4f0b32..e5696ce363617 100644 --- a/x-pack/plugins/security_solution_serverless/server/plugin.ts +++ b/x-pack/plugins/security_solution_serverless/server/plugin.ts @@ -13,6 +13,7 @@ import type { Logger, } from '@kbn/core/server'; +import { SECURITY_PROJECT_SETTINGS } from '@kbn/serverless-security-settings'; import { getProductAppFeatures } from '../common/pli/pli_features'; import type { ServerlessSecurityConfig } from './config'; @@ -89,6 +90,9 @@ export class SecuritySolutionServerlessPlugin taskManager: pluginsSetup.taskManager, cloudSetup: pluginsSetup.cloudSetup, }); + + pluginsSetup.serverless.setupProjectSettings(SECURITY_PROJECT_SETTINGS); + return {}; } diff --git a/x-pack/plugins/security_solution_serverless/server/types.ts b/x-pack/plugins/security_solution_serverless/server/types.ts index 63fb4d0685738..1beca2fc23b9d 100644 --- a/x-pack/plugins/security_solution_serverless/server/types.ts +++ b/x-pack/plugins/security_solution_serverless/server/types.ts @@ -20,6 +20,7 @@ import type { SecuritySolutionEssPluginSetup } from '@kbn/security-solution-ess/ import type { MlPluginSetup } from '@kbn/ml-plugin/server'; import type { FleetStartContract } from '@kbn/fleet-plugin/server'; +import type { ServerlessPluginSetup } from '@kbn/serverless/server'; import type { ProductTier } from '../common/product'; import type { ServerlessSecurityConfig } from './config'; @@ -33,6 +34,7 @@ export interface SecuritySolutionServerlessPluginSetupDeps { security: SecurityPluginSetup; securitySolution: SecuritySolutionPluginSetup; securitySolutionEss: SecuritySolutionEssPluginSetup; + serverless: ServerlessPluginSetup; features: PluginSetupContract; ml: MlPluginSetup; taskManager: TaskManagerSetupContract; diff --git a/x-pack/plugins/security_solution_serverless/tsconfig.json b/x-pack/plugins/security_solution_serverless/tsconfig.json index 2ad30566e55cd..636642b2a68d5 100644 --- a/x-pack/plugins/security_solution_serverless/tsconfig.json +++ b/x-pack/plugins/security_solution_serverless/tsconfig.json @@ -40,6 +40,7 @@ "@kbn/security-solution-features", "@kbn/cases-plugin", "@kbn/fleet-plugin", + "@kbn/serverless-security-settings", "@kbn/core-elasticsearch-server", "@kbn/usage-collection-plugin", "@kbn/cloud-defend-plugin" diff --git a/x-pack/plugins/serverless/jest.config.js b/x-pack/plugins/serverless/jest.config.js new file mode 100644 index 0000000000000..1b7860b8f3d78 --- /dev/null +++ b/x-pack/plugins/serverless/jest.config.js @@ -0,0 +1,15 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/x-pack/plugins/serverless'], + coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/serverless', + coverageReporters: ['text', 'html'], + collectCoverageFrom: ['/x-pack/plugins/serverless/{common,public,server}/**/*.{ts,tsx}'], +}; diff --git a/x-pack/plugins/serverless/server/mocks.ts b/x-pack/plugins/serverless/server/mocks.ts new file mode 100644 index 0000000000000..28b336d4b6c58 --- /dev/null +++ b/x-pack/plugins/serverless/server/mocks.ts @@ -0,0 +1,21 @@ +/* + * 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. + */ + +function createSetupContract() { + return { + setupProjectSettings: jest.fn(), + }; +} + +function createStartContract() { + return {}; +} + +export const serverlessPluginMock = { + createSetupContract, + createStartContract, +}; diff --git a/x-pack/plugins/serverless/server/plugin.test.ts b/x-pack/plugins/serverless/server/plugin.test.ts new file mode 100644 index 0000000000000..d002325368be6 --- /dev/null +++ b/x-pack/plugins/serverless/server/plugin.test.ts @@ -0,0 +1,39 @@ +/* + * 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. + */ + +import { coreMock } from '@kbn/core/server/mocks'; +import { config } from './config'; +import { ServerlessPlugin } from './plugin'; + +describe('Serverless Plugin', () => { + let plugin: ServerlessPlugin; + let mockCoreSetup: ReturnType; + let mockCoreStart: ReturnType; + beforeEach(() => { + plugin = new ServerlessPlugin( + coreMock.createPluginInitializerContext( + config.schema.validate({ + enabled: true, + }) + ) + ); + + mockCoreSetup = coreMock.createSetup({ + pluginStartContract: {}, + }); + mockCoreStart = coreMock.createStart(); + }); + + describe('start()', () => { + it('throws if project settings are not set up', () => { + plugin.setup(mockCoreSetup); + expect(() => plugin.start(mockCoreStart)).toThrowError( + "The uiSettings allowlist for serverless hasn't been set up. Make sure to set up your serverless project settings with setupProjectSettings()" + ); + }); + }); +}); diff --git a/x-pack/plugins/serverless/server/plugin.ts b/x-pack/plugins/serverless/server/plugin.ts index a2b1121d0c562..eefe74e6de903 100644 --- a/x-pack/plugins/serverless/server/plugin.ts +++ b/x-pack/plugins/serverless/server/plugin.ts @@ -13,6 +13,7 @@ import { schema, TypeOf } from '@kbn/config-schema'; import { getConfigDirectory } from '@kbn/utils'; import { ProjectType } from '@kbn/serverless-types'; +import { ALL_COMMON_SETTINGS } from '@kbn/serverless-common-settings'; import { ServerlessPluginSetup, ServerlessPluginStart } from './types'; import { ServerlessConfig } from './config'; import { API_SWITCH_PROJECT } from '../common'; @@ -35,6 +36,13 @@ const typeToIdMap: Record = { export class ServerlessPlugin implements Plugin { private readonly config: ServerlessConfig; + private projectSettingsAdded: boolean = false; + + private setupProjectSettings(core: CoreSetup, keys: string[]): void { + const settings = [...ALL_COMMON_SETTINGS].concat(keys); + core.uiSettings.setAllowlist(settings); + this.projectSettingsAdded = true; + } constructor(private readonly context: PluginInitializerContext) { this.config = this.context.config.get(); @@ -75,10 +83,17 @@ export class ServerlessPlugin implements Plugin this.setupProjectSettings(core, keys), + }; } public start(_core: CoreStart) { + if (!this.projectSettingsAdded) { + throw new Error( + "The uiSettings allowlist for serverless hasn't been set up. Make sure to set up your serverless project settings with setupProjectSettings()" + ); + } return {}; } diff --git a/x-pack/plugins/serverless/server/types.ts b/x-pack/plugins/serverless/server/types.ts index 92a804b34a948..71c06ce1b96b4 100644 --- a/x-pack/plugins/serverless/server/types.ts +++ b/x-pack/plugins/serverless/server/types.ts @@ -5,8 +5,9 @@ * 2.0. */ -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ServerlessPluginSetup {} +export interface ServerlessPluginSetup { + setupProjectSettings(keys: string[]): void; +} // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessPluginStart {} diff --git a/x-pack/plugins/serverless/tsconfig.json b/x-pack/plugins/serverless/tsconfig.json index 88f7b5af1636c..4bb3e35e34472 100644 --- a/x-pack/plugins/serverless/tsconfig.json +++ b/x-pack/plugins/serverless/tsconfig.json @@ -25,5 +25,6 @@ "@kbn/core-chrome-browser-internal", "@kbn/i18n-react", "@kbn/cloud-plugin", + "@kbn/serverless-common-settings", ] } diff --git a/x-pack/plugins/serverless_observability/server/plugin.ts b/x-pack/plugins/serverless_observability/server/plugin.ts index ae7bcd8baa064..c6e502f61ca8c 100644 --- a/x-pack/plugins/serverless_observability/server/plugin.ts +++ b/x-pack/plugins/serverless_observability/server/plugin.ts @@ -7,6 +7,7 @@ import type { PluginInitializerContext, Plugin, CoreSetup } from '@kbn/core/server'; +import { OBSERVABILITY_PROJECT_SETTINGS } from '@kbn/serverless-observability-settings'; import type { ServerlessObservabilityPluginSetup, ServerlessObservabilityPluginStart, @@ -27,6 +28,8 @@ export class ServerlessObservabilityPlugin public setup(_coreSetup: CoreSetup, pluginsSetup: SetupDependencies) { pluginsSetup.ml.setFeaturesEnabled({ ad: true, dfa: false, nlp: false }); + + pluginsSetup.serverless.setupProjectSettings(OBSERVABILITY_PROJECT_SETTINGS); return {}; } diff --git a/x-pack/plugins/serverless_observability/server/types.ts b/x-pack/plugins/serverless_observability/server/types.ts index 5ebad2274b9a5..d899efedb1617 100644 --- a/x-pack/plugins/serverless_observability/server/types.ts +++ b/x-pack/plugins/serverless_observability/server/types.ts @@ -6,6 +6,7 @@ */ import type { MlPluginSetup } from '@kbn/ml-plugin/server'; +import { ServerlessPluginSetup } from '@kbn/serverless/server'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessObservabilityPluginSetup {} @@ -17,4 +18,5 @@ export interface StartDependencies {} export interface SetupDependencies { ml: MlPluginSetup; + serverless: ServerlessPluginSetup; } diff --git a/x-pack/plugins/serverless_observability/tsconfig.json b/x-pack/plugins/serverless_observability/tsconfig.json index dec3814883e0e..8e88263a527bb 100644 --- a/x-pack/plugins/serverless_observability/tsconfig.json +++ b/x-pack/plugins/serverless_observability/tsconfig.json @@ -29,5 +29,6 @@ "@kbn/data-plugin", "@kbn/observability-plugin", "@kbn/io-ts-utils", + "@kbn/serverless-observability-settings", ] } diff --git a/x-pack/plugins/serverless_search/server/plugin.ts b/x-pack/plugins/serverless_search/server/plugin.ts index 693cdc1e7035e..e43c5b0f18bbb 100644 --- a/x-pack/plugins/serverless_search/server/plugin.ts +++ b/x-pack/plugins/serverless_search/server/plugin.ts @@ -13,6 +13,7 @@ import type { CoreSetup, } from '@kbn/core/server'; import type { SecurityPluginStart } from '@kbn/security-plugin/server'; +import { SEARCH_PROJECT_SETTINGS } from '@kbn/serverless-search-settings'; import { registerApiKeyRoutes } from './routes/api_key_routes'; import { registerIndicesRoutes } from './routes/indices_routes'; @@ -71,6 +72,7 @@ export class ServerlessSearchPlugin }); pluginsSetup.ml.setFeaturesEnabled({ ad: false, dfa: false, nlp: false }); + pluginsSetup.serverless.setupProjectSettings(SEARCH_PROJECT_SETTINGS); return {}; } diff --git a/x-pack/plugins/serverless_search/server/types.ts b/x-pack/plugins/serverless_search/server/types.ts index 8e8f7f15a8124..fe063c1a2aa5c 100644 --- a/x-pack/plugins/serverless_search/server/types.ts +++ b/x-pack/plugins/serverless_search/server/types.ts @@ -7,6 +7,7 @@ import type { SecurityPluginStart } from '@kbn/security-plugin/server'; import type { MlPluginSetup } from '@kbn/ml-plugin/server'; +import type { ServerlessPluginSetup } from '@kbn/serverless/server'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessSearchPluginSetup {} @@ -18,4 +19,5 @@ export interface StartDependencies { } export interface SetupDependencies { ml: MlPluginSetup; + serverless: ServerlessPluginSetup; } diff --git a/x-pack/plugins/serverless_search/tsconfig.json b/x-pack/plugins/serverless_search/tsconfig.json index c149beabd33ec..4e24925e4b3d9 100644 --- a/x-pack/plugins/serverless_search/tsconfig.json +++ b/x-pack/plugins/serverless_search/tsconfig.json @@ -31,6 +31,7 @@ "@kbn/management-cards-navigation", "@kbn/core-elasticsearch-server", "@kbn/search-api-panels", + "@kbn/serverless-search-settings", "@kbn/core-lifecycle-browser", "@kbn/react-kibana-context-theme", "@kbn/search-connectors", diff --git a/x-pack/test_serverless/functional/config.base.ts b/x-pack/test_serverless/functional/config.base.ts index 02ddf326fef8d..0f1eb73bbe2c7 100644 --- a/x-pack/test_serverless/functional/config.base.ts +++ b/x-pack/test_serverless/functional/config.base.ts @@ -62,6 +62,9 @@ export function createTestConfig(options: CreateTestConfigOptions) { indexManagement: { pathname: '/app/management/data/index_management', }, + advancedSettings: { + pathname: '/app/management/kibana/settings', + }, }, // choose where screenshots should be saved screenshots: { diff --git a/x-pack/test_serverless/functional/test_suites/common/advanced_settings.ts b/x-pack/test_serverless/functional/test_suites/common/advanced_settings.ts new file mode 100644 index 0000000000000..f24d3350b9744 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/advanced_settings.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. + */ + +import expect from '@kbn/expect'; +import { ALL_COMMON_SETTINGS } from '@kbn/serverless-common-settings'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const testSubjects = getService('testSubjects'); + const pageObjects = getPageObjects(['common']); + const browser = getService('browser'); + const retry = getService('retry'); + + // Skip until we enable the Advanced settings app in serverless + describe.skip('Common advanced settings', function () { + before(async () => { + await pageObjects.common.navigateToApp('advancedSettings'); + }); + + it('renders the page', async () => { + await retry.waitFor('title to be visible', async () => { + return await testSubjects.exists('managementSettingsTitle'); + }); + + const url = await browser.getCurrentUrl(); + expect(url).to.contain(`/settings`); + }); + + describe('renders common settings', () => { + for (const settingId of ALL_COMMON_SETTINGS) { + it('renders ' + settingId + ' edit field', async () => { + const isColorPickerField = + settingId === 'banners:textColor' || settingId === 'banners:backgroundColor'; + const fieldTestSubj = + (isColorPickerField ? 'euiColorPickerAnchor ' : '') + + 'advancedSetting-editField-' + + settingId; + expect(await testSubjects.exists(fieldTestSubj)).to.be(true); + }); + } + }); + }); +}; diff --git a/x-pack/test_serverless/functional/test_suites/common/index.ts b/x-pack/test_serverless/functional/test_suites/common/index.ts index 597a1b6f84963..89fe34c19f640 100644 --- a/x-pack/test_serverless/functional/test_suites/common/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/index.ts @@ -18,6 +18,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { // Management loadTestFile(require.resolve('./index_management')); + loadTestFile(require.resolve('./advanced_settings')); // Data View Management loadTestFile(require.resolve('./data_view_mgmt')); diff --git a/x-pack/test_serverless/functional/test_suites/observability/advanced_settings.ts b/x-pack/test_serverless/functional/test_suites/observability/advanced_settings.ts new file mode 100644 index 0000000000000..e723b81dbe20f --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/advanced_settings.ts @@ -0,0 +1,42 @@ +/* + * 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. + */ + +import expect from '@kbn/expect'; +import { OBSERVABILITY_PROJECT_SETTINGS } from '@kbn/serverless-observability-settings'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const testSubjects = getService('testSubjects'); + const pageObjects = getPageObjects(['common']); + const browser = getService('browser'); + const retry = getService('retry'); + + // Skip until we enable the Advanced settings app in serverless + describe.skip('Observability advanced settings', function () { + before(async () => { + await pageObjects.common.navigateToApp('advancedSettings'); + }); + + it('renders the page', async () => { + await retry.waitFor('title to be visible', async () => { + return await testSubjects.exists('managementSettingsTitle'); + }); + + const url = await browser.getCurrentUrl(); + expect(url).to.contain(`/settings`); + }); + + describe('renders observability settings', () => { + for (const settingId of OBSERVABILITY_PROJECT_SETTINGS) { + it('renders ' + settingId + ' edit field', async () => { + const fieldTestSubj = 'advancedSetting-editField-' + settingId; + expect(await testSubjects.exists(fieldTestSubj)).to.be(true); + }); + } + }); + }); +}; diff --git a/x-pack/test_serverless/functional/test_suites/observability/index.ts b/x-pack/test_serverless/functional/test_suites/observability/index.ts index 2d4c664085dbb..3c387337a23e5 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/index.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/index.ts @@ -17,5 +17,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./cases/configure')); loadTestFile(require.resolve('./cases/create_case_form')); loadTestFile(require.resolve('./cases/list_view')); + loadTestFile(require.resolve('./advanced_settings')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/search/advanced_settings.ts b/x-pack/test_serverless/functional/test_suites/search/advanced_settings.ts new file mode 100644 index 0000000000000..63b6053589ea6 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/search/advanced_settings.ts @@ -0,0 +1,42 @@ +/* + * 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. + */ + +import expect from '@kbn/expect'; +import { SEARCH_PROJECT_SETTINGS } from '@kbn/serverless-search-settings'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const testSubjects = getService('testSubjects'); + const pageObjects = getPageObjects(['common']); + const browser = getService('browser'); + const retry = getService('retry'); + + // Skip until we enable the Advanced settings app in serverless + describe.skip('Search advanced settings', function () { + before(async () => { + await pageObjects.common.navigateToApp('advancedSettings'); + }); + + it('renders the page', async () => { + await retry.waitFor('title to be visible', async () => { + return await testSubjects.exists('managementSettingsTitle'); + }); + + const url = await browser.getCurrentUrl(); + expect(url).to.contain(`/settings`); + }); + + describe('renders search settings', () => { + for (const settingId of SEARCH_PROJECT_SETTINGS) { + it('renders ' + settingId + ' edit field', async () => { + const fieldTestSubj = 'advancedSetting-editField-' + settingId; + expect(await testSubjects.exists(fieldTestSubj)).to.be(true); + }); + } + }); + }); +}; diff --git a/x-pack/test_serverless/functional/test_suites/search/index.ts b/x-pack/test_serverless/functional/test_suites/search/index.ts index e169f69f3f78b..fbaaf96aed8a4 100644 --- a/x-pack/test_serverless/functional/test_suites/search/index.ts +++ b/x-pack/test_serverless/functional/test_suites/search/index.ts @@ -16,5 +16,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./dashboards/build_dashboard')); loadTestFile(require.resolve('./dashboards/import_dashboard')); + loadTestFile(require.resolve('./advanced_settings')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/security/advanced_settings.ts b/x-pack/test_serverless/functional/test_suites/security/advanced_settings.ts new file mode 100644 index 0000000000000..27fa42549dcc6 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/security/advanced_settings.ts @@ -0,0 +1,42 @@ +/* + * 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. + */ + +import expect from '@kbn/expect'; +import { SECURITY_PROJECT_SETTINGS } from '@kbn/serverless-security-settings'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const testSubjects = getService('testSubjects'); + const pageObjects = getPageObjects(['common']); + const browser = getService('browser'); + const retry = getService('retry'); + + // Skip until we enable the Advanced settings app in serverless + describe.skip('Security advanced settings', function () { + before(async () => { + await pageObjects.common.navigateToApp('advancedSettings'); + }); + + it('renders the page', async () => { + await retry.waitFor('title to be visible', async () => { + return await testSubjects.exists('managementSettingsTitle'); + }); + + const url = await browser.getCurrentUrl(); + expect(url).to.contain(`/settings`); + }); + + describe('renders security settings', () => { + for (const settingId of SECURITY_PROJECT_SETTINGS) { + it('renders ' + settingId + ' edit field', async () => { + const fieldTestSubj = 'advancedSetting-editField-' + settingId; + expect(await testSubjects.exists(fieldTestSubj)).to.be(true); + }); + } + }); + }); +}; diff --git a/x-pack/test_serverless/functional/test_suites/security/index.ts b/x-pack/test_serverless/functional/test_suites/security/index.ts index b4c46b5f4c263..d68c184813cea 100644 --- a/x-pack/test_serverless/functional/test_suites/security/index.ts +++ b/x-pack/test_serverless/functional/test_suites/security/index.ts @@ -17,5 +17,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./ftr/cases/create_case_form')); loadTestFile(require.resolve('./ftr/cases/configure')); loadTestFile(require.resolve('./ftr/cases/list_view')); + loadTestFile(require.resolve('./advanced_settings')); }); } diff --git a/x-pack/test_serverless/tsconfig.json b/x-pack/test_serverless/tsconfig.json index 3950afef67928..1a94c23b6f1c1 100644 --- a/x-pack/test_serverless/tsconfig.json +++ b/x-pack/test_serverless/tsconfig.json @@ -54,5 +54,9 @@ "@kbn/bfetch-plugin", "@kbn/rison", "@kbn/std", + "@kbn/serverless-common-settings", + "@kbn/serverless-observability-settings", + "@kbn/serverless-search-settings", + "@kbn/serverless-security-settings", ] } diff --git a/yarn.lock b/yarn.lock index 1693ec6541874..51180726acd2e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4850,6 +4850,10 @@ version "0.0.0" uid "" +"@kbn/management-settings-ids@link:packages/kbn-management/settings/setting_ids": + version "0.0.0" + uid "" + "@kbn/management-settings-section-registry@link:packages/kbn-management/settings/section_registry": version "0.0.0" uid "" @@ -5458,6 +5462,14 @@ version "0.0.0" uid "" +"@kbn/serverless-common-settings@link:packages/serverless/settings/common": + version "0.0.0" + uid "" + +"@kbn/serverless-observability-settings@link:packages/serverless/settings/observability_project": + version "0.0.0" + uid "" + "@kbn/serverless-observability@link:x-pack/plugins/serverless_observability": version "0.0.0" uid "" @@ -5466,10 +5478,18 @@ version "0.0.0" uid "" +"@kbn/serverless-search-settings@link:packages/serverless/settings/search_project": + version "0.0.0" + uid "" + "@kbn/serverless-search@link:x-pack/plugins/serverless_search": version "0.0.0" uid "" +"@kbn/serverless-security-settings@link:packages/serverless/settings/security_project": + version "0.0.0" + uid "" + "@kbn/serverless-storybook-config@link:packages/serverless/storybook/config": version "0.0.0" uid ""