From 411ab215a50c773fa535e48e1b7a8199176eefb0 Mon Sep 17 00:00:00 2001 From: Julian Gernun <17549662+jcger@users.noreply.github.com> Date: Fri, 20 Jun 2025 16:10:43 +0200 Subject: [PATCH] [Response Ops][Connectors] New `xpack.actions.email.services.enabled` Kibana setting (#223363) ## Summary Closes #220288 ## Release note New kibana setting `xpack.actions.email.services.enabled` to enable/disable email services for email connector. --- .buildkite/ftr_platform_stateful_configs.yml | 3 +- .../alerting-settings.md | 6 + .../source/kibana-alert-action-settings.yml | 22 +++ .../resources/base/bin/kibana-docker | 1 + .../test_suites/core_plugins/rendering.ts | 1 + .../plugins/shared/actions/public/plugin.ts | 7 + .../actions/server/actions_config.mock.ts | 1 + .../actions/server/actions_config.test.ts | 52 ++++++ .../shared/actions/server/actions_config.ts | 15 +- .../shared/actions/server/config.test.ts | 49 +++++- .../plugins/shared/actions/server/config.ts | 45 ++++-- .../plugins/shared/actions/server/index.ts | 2 +- .../common/email/constants.ts | 15 ++ .../connector_types/email/email.test.tsx | 58 ++++++- .../public/connector_types/email/email.tsx | 32 +++- .../email/email_connector.test.tsx | 153 +++++++++++++++--- .../connector_types/email/email_connector.tsx | 15 +- .../public/connector_types/lib/test_utils.tsx | 1 + .../connector_types/email/index.test.ts | 70 ++++++++ .../server/connector_types/email/index.ts | 15 ++ .../application/components/test_utils.tsx | 2 +- .../public/application/connectors_app.tsx | 8 +- .../rules_list_sandbox.tsx | 4 +- .../public/application/rules_app.tsx | 4 +- .../common/lib/kibana/kibana_react.mock.ts | 2 +- .../triggers_actions_ui/public/mocks.ts | 2 +- .../triggers_actions_ui/public/plugin.ts | 1 + .../triggers_actions_ui/public/types.ts | 1 + .../config.ts | 0 .../email.ts | 0 .../index.ts | 0 .../config.ts | 30 ++++ .../email.ts | 33 ++++ .../index.ts | 21 +++ 34 files changed, 608 insertions(+), 63 deletions(-) create mode 100644 x-pack/platform/plugins/shared/stack_connectors/common/email/constants.ts rename x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/{with_aws_ses_kibana_config => with_email_aws_ses_kbn_config}/config.ts (100%) rename x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/{with_aws_ses_kibana_config => with_email_aws_ses_kbn_config}/email.ts (100%) rename x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/{with_aws_ses_kibana_config => with_email_aws_ses_kbn_config}/index.ts (100%) create mode 100644 x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/config.ts create mode 100644 x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/email.ts create mode 100644 x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/index.ts diff --git a/.buildkite/ftr_platform_stateful_configs.yml b/.buildkite/ftr_platform_stateful_configs.yml index 7b46c7c7890f..e17783b8206c 100644 --- a/.buildkite/ftr_platform_stateful_configs.yml +++ b/.buildkite/ftr_platform_stateful_configs.yml @@ -198,7 +198,8 @@ enabled: - x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/config.ts - x-pack/test/functional_with_es_ssl/apps/embeddable_alerts_table/config.ts - x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/config.ts - - x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_aws_ses_kibana_config/config.ts + - x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_aws_ses_kbn_config/config.ts + - x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/config.ts - x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/shared/config.ts - x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook_disabled_ssl_pfx/config.ts - x-pack/test/functional/apps/advanced_settings/config.ts diff --git a/docs/reference/configuration-reference/alerting-settings.md b/docs/reference/configuration-reference/alerting-settings.md index cb51d8437d82..f03e6744bb42 100644 --- a/docs/reference/configuration-reference/alerting-settings.md +++ b/docs/reference/configuration-reference/alerting-settings.md @@ -150,6 +150,12 @@ $$$action-config-email-domain-allowlist$$$ Data type: `int` Default: `465` +`xpack.actions.email.services.enabled` ![logo cloud](https://doc-icons.s3.us-east-2.amazonaws.com/logo_cloud.svg "Supported on {{ech}}") +: An array of strings indicating all email services that are enabled. Available options are `elastic-cloud`, `google-mail`, `microsoft-outlook`, `amazon-ses`, `microsoft-exchange`, and `other`. If the array is empty, no email services are enabled. The default value is `["*"]`, which enables all email services. + + Data type: `string` + Default: `["*"]` + `xpack.actions.enableFooterInEmail` ![logo cloud](https://doc-icons.s3.us-east-2.amazonaws.com/logo_cloud.svg "Supported on {{ech}}") : A boolean value indicating that a footer with a relevant link should be added to emails sent as alerting actions. diff --git a/docs/settings-gen/source/kibana-alert-action-settings.yml b/docs/settings-gen/source/kibana-alert-action-settings.yml index 767cac66aac3..f6f15fddd836 100644 --- a/docs/settings-gen/source/kibana-alert-action-settings.yml +++ b/docs/settings-gen/source/kibana-alert-action-settings.yml @@ -326,6 +326,28 @@ groups: ess: all # example: | + - setting: xpack.actions.email.services.enabled + id: action-config-email-services- + description: | + An array of strings indicating all email services that are enabled. Available options are `elastic-cloud`, `google-mail`, `microsoft-outlook`, `amazon-ses`, `microsoft-exchange`, and `other`. If the array is empty, no email services are enabled. The default value is `["*"]`, which enables all email services. + # state: deprecated/hidden/tech-preview + # deprecation_details: "" + # note: "" + # tip: "" + # warning: "" + # important: "" + datatype: enum + default: ["*"] + # options: + # - option: + # description: "" + # type: static/dynamic + applies_to: + deployment: + self: all + ess: all + # example: | + - setting: xpack.actions.enableFooterInEmail # id: description: | diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker index 15bad66cdfa1..4e0db2471c83 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker @@ -214,6 +214,7 @@ kibana_vars=( xpack.actions.email.domain_allowlist xpack.actions.email.services.ses.host xpack.actions.email.services.ses.port + xpack.actions.email.services.enabled xpack.actions.enableFooterInEmail xpack.actions.enabledActionTypes xpack.actions.maxResponseContentLength diff --git a/src/platform/test/plugin_functional/test_suites/core_plugins/rendering.ts b/src/platform/test/plugin_functional/test_suites/core_plugins/rendering.ts index 17206d91430b..f2ec000f8958 100644 --- a/src/platform/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/src/platform/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -203,6 +203,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'vis_type_xy.readOnly (boolean?|never)', 'vis_type_vega.enableExternalUrls (boolean?)', 'xpack.actions.email.domain_allowlist (array?)', + 'xpack.actions.email.services.enabled (array?)', 'xpack.actions.webhook.ssl.pfx.enabled (boolean?)', 'xpack.apm.serviceMapEnabled (boolean?)', 'xpack.apm.ui.enabled (boolean?)', diff --git a/x-pack/platform/plugins/shared/actions/public/plugin.ts b/x-pack/platform/plugins/shared/actions/public/plugin.ts index e773d4016b32..d2bf341e8e52 100644 --- a/x-pack/platform/plugins/shared/actions/public/plugin.ts +++ b/x-pack/platform/plugins/shared/actions/public/plugin.ts @@ -14,12 +14,16 @@ export interface ActionsPublicPluginSetup { emails: string[], options?: ValidateEmailAddressesOptions ): ValidatedEmail[]; + enabledEmailServices: string[]; isWebhookSslWithPfxEnabled?: boolean; } export interface Config { email: { domain_allowlist: string[]; + services: { + enabled: string[]; + }; }; webhook: { ssl: { @@ -32,11 +36,13 @@ export interface Config { export class Plugin implements CorePlugin { private readonly allowedEmailDomains: string[] | null = null; + private readonly enabledEmailServices: string[]; private readonly webhookSslWithPfxEnabled: boolean; constructor(ctx: PluginInitializerContext) { const config = ctx.config.get(); this.allowedEmailDomains = config.email?.domain_allowlist || null; + this.enabledEmailServices = Array.from(new Set(config.email?.services?.enabled || ['*'])); this.webhookSslWithPfxEnabled = config.webhook?.ssl.pfx.enabled ?? true; } @@ -44,6 +50,7 @@ export class Plugin implements CorePlugin { return { validateEmailAddresses: (emails: string[], options: ValidateEmailAddressesOptions) => validateEmails(this.allowedEmailDomains, emails, options), + enabledEmailServices: this.enabledEmailServices, isWebhookSslWithPfxEnabled: this.webhookSslWithPfxEnabled, }; } diff --git a/x-pack/platform/plugins/shared/actions/server/actions_config.mock.ts b/x-pack/platform/plugins/shared/actions/server/actions_config.mock.ts index 2ac5f73f356f..5ac6caa9c3f9 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_config.mock.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_config.mock.ts @@ -44,6 +44,7 @@ const createActionsConfigMock = () => { }, }), getAwsSesConfig: jest.fn().mockReturnValue(null), + getEnabledEmailServices: jest.fn().mockReturnValue(['*']), }; return mocked; }; diff --git a/x-pack/platform/plugins/shared/actions/server/actions_config.test.ts b/x-pack/platform/plugins/shared/actions/server/actions_config.test.ts index bfd170f4d5dc..7d89aae14040 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_config.test.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_config.test.ts @@ -633,6 +633,14 @@ describe('getAwsSesConfig()', () => { expect(acu.getAwsSesConfig()).toEqual(null); }); + test('returns null when no email.services.ses config set', () => { + const acu = getActionsConfigurationUtilities({ + ...defaultActionsConfig, + email: { services: {} }, + }); + expect(acu.getAwsSesConfig()).toEqual(null); + }); + test('returns config if set', () => { const acu = getActionsConfigurationUtilities({ ...defaultActionsConfig, @@ -652,3 +660,47 @@ describe('getAwsSesConfig()', () => { }); }); }); + +describe('getEnabledEmailServices()', () => { + test('returns all services when no email config set', () => { + const acu = getActionsConfigurationUtilities(defaultActionsConfig); + expect(acu.getEnabledEmailServices()).toEqual(['*']); + }); + + test('returns all services when no email.services config set', () => { + const acu = getActionsConfigurationUtilities({ ...defaultActionsConfig, email: {} }); + expect(acu.getEnabledEmailServices()).toEqual(['*']); + }); + + test('returns all services when no email.services.enabled config set', () => { + const acu = getActionsConfigurationUtilities({ + ...defaultActionsConfig, + email: { services: {} }, + }); + expect(acu.getEnabledEmailServices()).toEqual(['*']); + }); + + test('returns only enabled services', () => { + const acu = getActionsConfigurationUtilities({ + ...defaultActionsConfig, + email: { + services: { + enabled: ['google-mail', 'microsoft-exchange'], + }, + }, + }); + expect(acu.getEnabledEmailServices()).toEqual(['google-mail', 'microsoft-exchange']); + }); + + test('returns all services when enabled is set to "*" in config', () => { + const acu = getActionsConfigurationUtilities({ + ...defaultActionsConfig, + email: { + services: { + enabled: ['*'], + }, + }, + }); + expect(acu.getEnabledEmailServices()).toEqual(['*']); + }); +}); diff --git a/x-pack/platform/plugins/shared/actions/server/actions_config.ts b/x-pack/platform/plugins/shared/actions/server/actions_config.ts index b771ae0ba0e2..a39d31dac47c 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_config.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_config.ts @@ -63,6 +63,7 @@ export interface ActionsConfigurationUtilities { }; }; getAwsSesConfig: () => AwsSesConfig; + getEnabledEmailServices: () => string[]; } function allowListErrorMessage(field: AllowListingField, value: string) { @@ -243,15 +244,23 @@ export function getActionsConfigurationUtilities( }; }, getAwsSesConfig: () => { - if (config.email?.services?.ses.host && config.email?.services?.ses.port) { + if (config.email?.services?.ses?.host && config.email?.services?.ses?.port) { return { - host: config.email?.services?.ses.host, - port: config.email?.services?.ses.port, + host: config.email?.services?.ses?.host, + port: config.email?.services?.ses?.port, secure: true, }; } return null; }, + getEnabledEmailServices() { + const emailServices = config.email?.services?.enabled; + if (emailServices) { + return Array.from(new Set(Array.from(emailServices))); + } + + return ['*']; + }, }; } diff --git a/x-pack/platform/plugins/shared/actions/server/config.test.ts b/x-pack/platform/plugins/shared/actions/server/config.test.ts index d9493cb85503..b1f0d39fd06f 100644 --- a/x-pack/platform/plugins/shared/actions/server/config.test.ts +++ b/x-pack/platform/plugins/shared/actions/server/config.test.ts @@ -238,7 +238,7 @@ describe('config validation', () => { config.email = {}; expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot( - `"[email]: Email configuration requires either domain_allowlist or services.ses to be specified"` + `"[email]: email.domain_allowlist or email.services must be defined"` ); config.email = { domain_allowlist: [] }; @@ -285,35 +285,35 @@ describe('config validation', () => { test('validates empty email config', () => { config.email = {}; expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot( - `"[email]: Email configuration requires either domain_allowlist or services.ses to be specified"` + `"[email]: email.domain_allowlist or email.services must be defined"` ); }); test('validates email config with empty services', () => { config.email = { services: {} }; expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot( - `"[email]: Email configuration requires either domain_allowlist or services.ses to be specified"` + `"[email.services]: email.services.enabled or email.services.ses must be defined"` ); }); test('validates email config with empty ses service', () => { config.email = { services: { ses: {} } }; expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot( - `"[email]: Email configuration requires either domain_allowlist or services.ses to be specified"` + `"[email.services.ses.host]: expected value of type [string] but got [undefined]"` ); }); test('validates ses config with host only', () => { config.email = { services: { ses: { host: 'ses.host.com' } } }; expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot( - `"[email]: Email configuration requires both services.ses.host and services.ses.port to be specified"` + `"[email.services.ses.port]: expected value of type [number] but got [undefined]"` ); }); test('validates ses config with port only', () => { config.email = { services: { ses: { port: 1 } } }; expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot( - `"[email]: Email configuration requires both services.ses.host and services.ses.port to be specified"` + `"[email.services.ses.host]: expected value of type [string] but got [undefined]"` ); }); @@ -323,6 +323,43 @@ describe('config validation', () => { expect(result.email?.services?.ses).toEqual({ host: 'ses.host.com', port: 1 }); }); }); + + describe('email.services.enabled', () => { + const config: Record = {}; + test('validates email config with empty enabled services', () => { + config.email = { services: { enabled: [] } }; + expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot( + `"[email.services.enabled]: array size is [0], but cannot be smaller than [1]"` + ); + }); + + test('validates email config with enabled services', () => { + config.email = { services: { enabled: ['elastic-cloud', 'amazon-ses'] } }; + const result = configSchema.validate(config); + expect(result.email?.services?.enabled).toEqual(['elastic-cloud', 'amazon-ses']); + }); + + test('validates email config with unexistend service', () => { + config.email = { services: { enabled: ['fake-service'] } }; + expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot(` + "[email.services.enabled.0]: types that failed validation: + - [email.services.enabled.0.0]: expected value to equal [google-mail] + - [email.services.enabled.0.1]: expected value to equal [microsoft-exchange] + - [email.services.enabled.0.2]: expected value to equal [microsoft-outlook] + - [email.services.enabled.0.3]: expected value to equal [amazon-ses] + - [email.services.enabled.0.4]: expected value to equal [elastic-cloud] + - [email.services.enabled.0.5]: expected value to equal [other] + - [email.services.enabled.0.6]: expected value to equal [*]" + `); + }); + + test('validates enabled services but no ses service', () => { + config.email = { services: { enabled: ['google-mail', 'amazon-ses'] } }; + const result = configSchema.validate(config); + expect(result.email?.services?.enabled).toEqual(['google-mail', 'amazon-ses']); + expect(result.email?.services?.ses).toBeUndefined(); + }); + }); }); // object creator that ensures we can create a property named __proto__ on an diff --git a/x-pack/platform/plugins/shared/actions/server/config.ts b/x-pack/platform/plugins/shared/actions/server/config.ts index 794547e68226..db290577cf07 100644 --- a/x-pack/platform/plugins/shared/actions/server/config.ts +++ b/x-pack/platform/plugins/shared/actions/server/config.ts @@ -125,22 +125,43 @@ export const configSchema = schema.object({ { domain_allowlist: schema.maybe(schema.arrayOf(schema.string())), services: schema.maybe( - schema.object({ - ses: schema.object({ - host: schema.maybe(schema.string({ minLength: 1 })), - port: schema.maybe(schema.number({ min: 1, max: 65535 })), - }), - }) + schema.object( + { + enabled: schema.maybe( + schema.arrayOf( + schema.oneOf([ + schema.literal('google-mail'), + schema.literal('microsoft-exchange'), + schema.literal('microsoft-outlook'), + schema.literal('amazon-ses'), + schema.literal('elastic-cloud'), + schema.literal('other'), + schema.literal('*'), + ]), + { minSize: 1 } + ) + ), + ses: schema.maybe( + schema.object({ + host: schema.string({ minLength: 1 }), + port: schema.number({ min: 1, max: 65535 }), + }) + ), + }, + { + validate: (obj) => { + if (obj && Object.keys(obj).length === 0) { + return 'email.services.enabled or email.services.ses must be defined'; + } + }, + } + ) ), }, { validate: (obj) => { - if (!obj.domain_allowlist && !obj.services?.ses.host && !obj.services?.ses.port) { - return 'Email configuration requires either domain_allowlist or services.ses to be specified'; - } - - if (obj.services?.ses && (!obj.services.ses.host || !obj.services.ses.port)) { - return 'Email configuration requires both services.ses.host and services.ses.port to be specified'; + if (obj && Object.keys(obj).length === 0) { + return 'email.domain_allowlist or email.services must be defined'; } }, } diff --git a/x-pack/platform/plugins/shared/actions/server/index.ts b/x-pack/platform/plugins/shared/actions/server/index.ts index 2aa202a401b2..5210d2f146cd 100644 --- a/x-pack/platform/plugins/shared/actions/server/index.ts +++ b/x-pack/platform/plugins/shared/actions/server/index.ts @@ -50,7 +50,7 @@ export type { ServiceParams } from './sub_action_framework/types'; export const config: PluginConfigDescriptor = { schema: configSchema, exposeToBrowser: { - email: { domain_allowlist: true }, + email: { domain_allowlist: true, services: { enabled: true } }, webhook: { ssl: { pfx: { enabled: true } } }, }, }; diff --git a/x-pack/platform/plugins/shared/stack_connectors/common/email/constants.ts b/x-pack/platform/plugins/shared/stack_connectors/common/email/constants.ts new file mode 100644 index 000000000000..2cf6077cb4bb --- /dev/null +++ b/x-pack/platform/plugins/shared/stack_connectors/common/email/constants.ts @@ -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. + */ + +export const serviceParamValueToKbnSettingMap = { + gmail: 'google-mail', + outlook365: 'microsoft-outlook', + ses: 'amazon-ses', + elastic_cloud: 'elastic-cloud', + exchange_server: 'microsoft-exchange', + other: 'other', +} as const; diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email.test.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email.test.tsx index 34b141296b31..5c17c17c34b5 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email.test.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email.test.tsx @@ -8,7 +8,7 @@ import { TypeRegistry } from '@kbn/triggers-actions-ui-plugin/public/application/type_registry'; import { registerConnectorTypes } from '..'; import type { ActionTypeModel as ConnectorTypeModel } from '@kbn/triggers-actions-ui-plugin/public/types'; -import { getEmailServices } from './email'; +import { emailServices, getEmailServices } from './email'; import { ValidatedEmail, InvalidEmailReason, @@ -17,6 +17,7 @@ import { } from '@kbn/actions-plugin/common'; import { experimentalFeaturesMock } from '../../mocks'; import { ExperimentalFeaturesService } from '../../common/experimental_features_service'; +import { serviceParamValueToKbnSettingMap } from '../../../common/email/constants'; const CONNECTOR_TYPE_ID = '.email'; let connectorTypeModel: ConnectorTypeModel; @@ -65,14 +66,65 @@ describe('connectorTypeRegistry.get() works', () => { describe('getEmailServices', () => { test('should return elastic cloud service if isCloudEnabled is true', () => { - const services = getEmailServices(true); + const services = getEmailServices(true, ['*']); expect(services.find((service) => service.value === 'elastic_cloud')).toBeTruthy(); }); test('should not return elastic cloud service if isCloudEnabled is false', () => { - const services = getEmailServices(false); + const services = getEmailServices(false, ['*']); expect(services.find((service) => service.value === 'elastic_cloud')).toBeFalsy(); }); + + test('should return all services if enabledEmailsServices is *', () => { + const services = getEmailServices(true, ['*']); + expect(services).toEqual(emailServices); + }); + + test('should return only specified services if enabledEmailsServices is not empty', () => { + const services = getEmailServices(true, [ + serviceParamValueToKbnSettingMap.gmail, + serviceParamValueToKbnSettingMap.outlook365, + ]); + + expect(services).toEqual([ + { + ['kbn-setting-value']: 'google-mail', + text: 'Gmail', + value: 'gmail', + }, + { + ['kbn-setting-value']: 'microsoft-outlook', + text: 'Outlook', + value: 'outlook365', + }, + ]); + }); + + test('should return enabled services and the current service if specified', () => { + const services = getEmailServices( + true, + [serviceParamValueToKbnSettingMap.gmail, serviceParamValueToKbnSettingMap.outlook365], + serviceParamValueToKbnSettingMap.other + ); + + expect(services).toEqual([ + { + ['kbn-setting-value']: 'google-mail', + text: 'Gmail', + value: 'gmail', + }, + { + ['kbn-setting-value']: 'microsoft-outlook', + text: 'Outlook', + value: 'outlook365', + }, + { + ['kbn-setting-value']: 'other', + text: 'Other', + value: 'other', + }, + ]); + }); }); describe('action params validation', () => { diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email.tsx index cc35337fb17c..332f3adc3625 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email.tsx @@ -16,50 +16,76 @@ import type { } from '@kbn/triggers-actions-ui-plugin/public/types'; import { EmailActionParams, EmailConfig, EmailSecrets } from '../types'; import { RegistrationServices } from '..'; +import { serviceParamValueToKbnSettingMap as emailKbnSettings } from '../../../common/email/constants'; -const emailServices: EuiSelectOption[] = [ +export const emailServices: Array = [ { text: i18n.translate('xpack.stackConnectors.components.email.gmailServerTypeLabel', { defaultMessage: 'Gmail', }), value: 'gmail', + ['kbn-setting-value']: emailKbnSettings.gmail, }, { text: i18n.translate('xpack.stackConnectors.components.email.outlookServerTypeLabel', { defaultMessage: 'Outlook', }), value: 'outlook365', + ['kbn-setting-value']: emailKbnSettings.outlook365, }, { text: i18n.translate('xpack.stackConnectors.components.email.amazonSesServerTypeLabel', { defaultMessage: 'Amazon SES', }), value: 'ses', + ['kbn-setting-value']: emailKbnSettings.ses, }, { text: i18n.translate('xpack.stackConnectors.components.email.elasticCloudServerTypeLabel', { defaultMessage: 'Elastic Cloud', }), value: 'elastic_cloud', + ['kbn-setting-value']: emailKbnSettings.elastic_cloud, }, { text: i18n.translate('xpack.stackConnectors.components.email.exchangeServerTypeLabel', { defaultMessage: 'MS Exchange Server', }), value: 'exchange_server', + ['kbn-setting-value']: emailKbnSettings.exchange_server, }, { text: i18n.translate('xpack.stackConnectors.components.email.otherServerTypeLabel', { defaultMessage: 'Other', }), value: 'other', + ['kbn-setting-value']: emailKbnSettings.other, }, ]; -export function getEmailServices(isCloudEnabled: boolean) { - return isCloudEnabled +// Return the current service regardless of its enabled state to allow users to: +// 1. View the current service in the dropdown UI +// 2. Update the service configuration if needed +// Note: The connector update endpoint will reject updates where the service +// remains unchanged but is disabled. +export function getEmailServices( + isCloudEnabled: boolean, + enabledEmailsServices: string[], + currentService?: string +): Array { + const allEmailServices = isCloudEnabled ? emailServices : emailServices.filter((service) => service.value !== 'elastic_cloud'); + + if (enabledEmailsServices.includes('*')) { + return allEmailServices; + } + + return allEmailServices.filter( + (service) => + service.value === currentService || + enabledEmailsServices.includes(service['kbn-setting-value']) + ); } export function getConnectorType( diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email_connector.test.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email_connector.test.tsx index cee1d9f876ff..e177c17968ab 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email_connector.test.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email_connector.test.tsx @@ -7,22 +7,34 @@ import React, { Suspense } from 'react'; import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { act } from '@testing-library/react'; +import { act, screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; import EmailActionConnectorFields from './email_connector'; -import * as hooks from './use_email_config'; import { AppMockRenderer, ConnectorFormTestProvider, createAppMockRenderer, waitForComponentToUpdate, } from '../lib/test_utils'; +import { getServiceConfig } from './api'; jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana'); const useKibanaMock = useKibana as jest.Mocked; +jest.mock('./api', () => { + return { + getServiceConfig: jest.fn(), + }; +}); + describe('EmailActionConnectorFields', () => { + const enabledEmailServices = ['*']; + + afterEach(() => { + jest.clearAllMocks(); + }); + test('all connector fields are rendered', async () => { const actionConnector = { secrets: { @@ -170,12 +182,11 @@ describe('EmailActionConnectorFields', () => { }); test('host, port and secure fields should be disabled when service field is set to well known service', async () => { - const getEmailServiceConfig = jest - .fn() - .mockResolvedValue({ host: 'https://example.com', port: 80, secure: false }); - jest - .spyOn(hooks, 'useEmailConfig') - .mockImplementation(() => ({ isLoading: false, getEmailServiceConfig })); + (getServiceConfig as jest.Mock).mockResolvedValue({ + host: 'https://example.com', + port: 80, + secure: false, + }); const actionConnector = { secrets: { @@ -214,12 +225,11 @@ describe('EmailActionConnectorFields', () => { }); test('host, port and secure fields should not be disabled when service field is set to other', async () => { - const getEmailServiceConfig = jest - .fn() - .mockResolvedValue({ host: 'https://example.com', port: 80, secure: false }); - jest - .spyOn(hooks, 'useEmailConfig') - .mockImplementation(() => ({ isLoading: false, getEmailServiceConfig })); + (getServiceConfig as jest.Mock).mockResolvedValue({ + host: 'https://example.com', + port: 80, + secure: false, + }); const actionConnector = { secrets: { @@ -292,7 +302,7 @@ describe('EmailActionConnectorFields', () => { { { { { { { { { }); }); }); + +describe('when not all email services are enabled', () => { + const enabledEmailServices = ['amazon-ses', 'other', 'microsoft-exchange']; + let appMockRenderer: AppMockRenderer; + const onSubmit = jest.fn(); + const validateEmailAddresses = jest.fn(); + + beforeEach(() => { + appMockRenderer = createAppMockRenderer(); + validateEmailAddresses.mockReturnValue([{ valid: true }]); + (getServiceConfig as jest.Mock).mockResolvedValue({ + host: 'https://example.com', + port: 2255, + secure: true, + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('only allows enabled services to be selected only', async () => { + const actionConnector = { + secrets: { + user: 'user', + password: 'pass', + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: {}, + isDeprecated: false, + }; + + appMockRenderer.render( + + {}} + /> + + ); + + const emailServiceSelect = screen.getByTestId('emailServiceSelectInput') as HTMLSelectElement; + + const options = within(emailServiceSelect).getAllByRole('option'); + expect(options).toHaveLength(3); + expect(options[0].textContent).toBe('Amazon SES'); + expect(options[1].textContent).toBe('MS Exchange Server'); + expect(options[2].textContent).toBe('Other'); + }); + + it('adds the current connector service to the service list even if not enabled', async () => { + const actionConnector = { + secrets: { + user: 'user', + password: 'pass', + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + from: 'test@test.com', + test: 'test', + service: 'gmail', // not enabled + secure: true, + }, + isDeprecated: false, + }; + + appMockRenderer.render( + + {}} + /> + + ); + + const emailServiceSelect = screen.getByTestId('emailServiceSelectInput') as HTMLSelectElement; + + const options = within(emailServiceSelect).getAllByRole('option'); + expect(options).toHaveLength(4); + expect(options[0].textContent).toBe('Gmail'); + expect(options[1].textContent).toBe('Amazon SES'); + expect(options[2].textContent).toBe('MS Exchange Server'); + expect(options[3].textContent).toBe('Other'); + }); +}); diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email_connector.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email_connector.tsx index bfff63877679..89c2f337c54e 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email_connector.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/email/email_connector.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { lazy, useEffect, useMemo } from 'react'; +import React, { lazy, useEffect, useMemo, useRef } from 'react'; import { isEmpty } from 'lodash'; import { EuiFlexItem, EuiFlexGroup, EuiTitle, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -102,7 +102,7 @@ export const EmailActionConnectorFields: React.FunctionComponent { async function fetchConfig() { @@ -173,7 +182,7 @@ export const EmailActionConnectorFields: React.FunctionComponent = ({ connectorServices = { validateEmailAddresses: jest.fn(), isWebhookSslWithPfxEnabled: true, + enabledEmailServices: ['*'], }, }) => { const { form } = useForm({ defaultValue }); diff --git a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/email/index.test.ts b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/email/index.test.ts index f9e060c9c5a1..a0f1ab20ae20 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/email/index.test.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/email/index.test.ts @@ -34,6 +34,7 @@ import { getConnectorType } from '.'; import type { ValidateEmailAddressesOptions } from '@kbn/actions-plugin/common'; import { ActionExecutionSourceType } from '@kbn/actions-plugin/server/types'; import { AdditionalEmailServices } from '../../../common'; +import { serviceParamValueToKbnSettingMap } from '../../../common/email/constants'; const sendEmailMock = sendEmail as jest.Mock; @@ -503,6 +504,75 @@ describe('params validation', () => { ); }).not.toThrowError(); }); + + test('error when using a service that is not enabled', async () => { + const configUtils = actionsConfigMock.create(); + configUtils.getEnabledEmailServices = jest + .fn() + .mockReturnValue([ + serviceParamValueToKbnSettingMap.gmail, + serviceParamValueToKbnSettingMap.elastic_cloud, + ]); + + expect(() => + validateConfig( + connectorType, + { + service: 'other', + from: 'bob@example.com', + host: 'wrong-host', + port: 123, + secure: true, + hasAuth: true, + }, + { configurationUtilities: configUtils } + ) + ).toThrowErrorMatchingInlineSnapshot( + `"error validating action type config: [service]: \\"other\\" is not in the list of enabled email services: google-mail,elastic-cloud"` + ); + }); + + test('no error using enabled services = *', async () => { + const configUtils = actionsConfigMock.create(); + configUtils.getEnabledEmailServices = jest.fn().mockReturnValue(['*']); + + expect(() => + validateConfig( + connectorType, + { + service: 'other', + from: 'bob@example.com', + host: 'wrong-host', + port: 123, + secure: true, + hasAuth: true, + }, + { configurationUtilities: configUtils } + ) + ).not.toThrowError(); + }); + + test('does not throw when fetching service enabled in config', () => { + const configUtils = actionsConfigMock.create(); + configUtils.getEnabledEmailServices = jest + .fn() + .mockReturnValue([serviceParamValueToKbnSettingMap.elastic_cloud]); + + expect(() => + validateConfig( + connectorType, + { + service: 'elastic_cloud', + from: 'bob@example.com', + host: 'dockerhost', + port: 10025, + secure: false, + hasAuth: false, + }, + { configurationUtilities: configUtils } + ) + ).not.toThrowError(); + }); }); describe('execute()', () => { diff --git a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/email/index.ts b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/email/index.ts index 189abf313eea..c002aa051556 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/email/index.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/email/index.ts @@ -34,6 +34,7 @@ import { AdditionalEmailServices } from '../../../common'; import type { SendEmailOptions, Transport } from './send_email'; import { sendEmail, JSON_TRANSPORT_SERVICE } from './send_email'; import { portSchema } from '../lib/schemas'; +import { serviceParamValueToKbnSettingMap as emailKbnSettings } from '../../../common/email/constants'; export type EmailConnectorType = ConnectorType< ConnectorTypeConfigType, @@ -82,6 +83,20 @@ function validateConfig( const config = configObject; const { configurationUtilities } = validatorServices; const awsSesConfig = configurationUtilities.getAwsSesConfig(); + const enabledServices = configurationUtilities.getEnabledEmailServices(); + + const serviceKey = config.service as keyof typeof emailKbnSettings; + if ( + !enabledServices.includes('*') && + config.service in emailKbnSettings && + !enabledServices.includes(emailKbnSettings[serviceKey]) + ) { + throw new Error( + `[service]: "${ + emailKbnSettings[serviceKey] + }" is not in the list of enabled email services: ${enabledServices.join(',')}` + ); + } const emails = [config.from]; const invalidEmailsMessage = configurationUtilities.validateEmailAddresses(emails); diff --git a/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/components/test_utils.tsx b/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/components/test_utils.tsx index e4ed6e02e2ac..689e31c08d0d 100644 --- a/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/components/test_utils.tsx +++ b/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/components/test_utils.tsx @@ -24,7 +24,7 @@ const FormTestProviderComponent: React.FC = ({ children, defaultValue, onSubmit, - connectorServices = { validateEmailAddresses: jest.fn() }, + connectorServices = { validateEmailAddresses: jest.fn(), enabledEmailServices: ['*'] }, }) => { const { form } = useForm({ defaultValue }); const { submit } = form; diff --git a/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/connectors_app.tsx b/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/connectors_app.tsx index 6b4270a0ed42..f66ca07e3e86 100644 --- a/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/connectors_app.tsx +++ b/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/connectors_app.tsx @@ -90,11 +90,15 @@ export const App = ({ deps }: { deps: TriggersAndActionsUiServices }) => { export const AppWithoutRouter = ({ sectionsRegex }: { sectionsRegex: string }) => { const { - actions: { validateEmailAddresses, isWebhookSslWithPfxEnabled }, + actions: { validateEmailAddresses, enabledEmailServices, isWebhookSslWithPfxEnabled }, } = useKibana().services; return ( - + { const { - services: { validateEmailAddresses }, + services: { validateEmailAddresses, enabledEmailServices }, } = useConnectorContext(); return (
{getRulesListLazy({ - connectorServices: { validateEmailAddresses }, + connectorServices: { validateEmailAddresses, enabledEmailServices }, rulesListProps: {}, })}
diff --git a/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/rules_app.tsx b/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/rules_app.tsx index 1680711739e0..dba5bf030199 100644 --- a/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/rules_app.tsx +++ b/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/rules_app.tsx @@ -120,12 +120,12 @@ export const App = ({ deps }: { deps: TriggersAndActionsUiServices }) => { export const AppWithoutRouter = ({ sectionsRegex }: { sectionsRegex: string }) => { const { - actions: { validateEmailAddresses }, + actions: { validateEmailAddresses, enabledEmailServices }, application: { navigateToApp }, } = useKibana().services; return ( - + { const licensingPluginMock = licensingMock.createStart(); return { ...core, - actions: { validateEmailAddresses: jest.fn() }, + actions: { validateEmailAddresses: jest.fn(), enabledEmailServices: ['*'] }, ruleTypeRegistry: { has: jest.fn(), register: jest.fn(), diff --git a/x-pack/platform/plugins/shared/triggers_actions_ui/public/mocks.ts b/x-pack/platform/plugins/shared/triggers_actions_ui/public/mocks.ts index eeeaa121eac7..695b1e90821c 100644 --- a/x-pack/platform/plugins/shared/triggers_actions_ui/public/mocks.ts +++ b/x-pack/platform/plugins/shared/triggers_actions_ui/public/mocks.ts @@ -49,7 +49,7 @@ import { getUntrackModalLazy } from './common/get_untrack_modal'; function createStartMock(): TriggersAndActionsUIPublicPluginStart { const actionTypeRegistry = new TypeRegistry(); const ruleTypeRegistry = new TypeRegistry(); - const connectorServices = { validateEmailAddresses: jest.fn() }; + const connectorServices = { validateEmailAddresses: jest.fn(), enabledEmailServices: ['*'] }; return { actionTypeRegistry, ruleTypeRegistry, diff --git a/x-pack/platform/plugins/shared/triggers_actions_ui/public/plugin.ts b/x-pack/platform/plugins/shared/triggers_actions_ui/public/plugin.ts index 01803a7c4c85..501b584afcd0 100644 --- a/x-pack/platform/plugins/shared/triggers_actions_ui/public/plugin.ts +++ b/x-pack/platform/plugins/shared/triggers_actions_ui/public/plugin.ts @@ -205,6 +205,7 @@ export class Plugin const ruleTypeRegistry = this.ruleTypeRegistry; this.connectorServices = { validateEmailAddresses: plugins.actions.validateEmailAddresses, + enabledEmailServices: plugins.actions.enabledEmailServices, }; ExperimentalFeaturesService.init({ experimentalFeatures: this.experimentalFeatures }); diff --git a/x-pack/platform/plugins/shared/triggers_actions_ui/public/types.ts b/x-pack/platform/plugins/shared/triggers_actions_ui/public/types.ts index 4464b6e54b61..5fb31c7dde81 100644 --- a/x-pack/platform/plugins/shared/triggers_actions_ui/public/types.ts +++ b/x-pack/platform/plugins/shared/triggers_actions_ui/public/types.ts @@ -400,6 +400,7 @@ export interface SnoozeSchedule { export interface ConnectorServices { validateEmailAddresses: ActionsPublicPluginSetup['validateEmailAddresses']; + enabledEmailServices: ActionsPublicPluginSetup['enabledEmailServices']; isWebhookSslWithPfxEnabled?: ActionsPublicPluginSetup['isWebhookSslWithPfxEnabled']; } diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_aws_ses_kibana_config/config.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_aws_ses_kbn_config/config.ts similarity index 100% rename from x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_aws_ses_kibana_config/config.ts rename to x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_aws_ses_kbn_config/config.ts diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_aws_ses_kibana_config/email.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_aws_ses_kbn_config/email.ts similarity index 100% rename from x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_aws_ses_kibana_config/email.ts rename to x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_aws_ses_kbn_config/email.ts diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_aws_ses_kibana_config/index.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_aws_ses_kbn_config/index.ts similarity index 100% rename from x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_aws_ses_kibana_config/index.ts rename to x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_aws_ses_kbn_config/index.ts diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/config.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/config.ts new file mode 100644 index 000000000000..1eff585dd389 --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/config.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const emailEnabledServices = ['google-mail', 'amazon-ses']; + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseConfig = await readConfigFile(require.resolve('../../../../config.base.ts')); + + return { + ...baseConfig.getAll(), + testFiles: [require.resolve('.')], + junit: { + reportName: + 'Chrome X-Pack UI Functional Tests with ES SSL - Email services enabled Kibana config', + }, + kbnTestServer: { + ...baseConfig.getAll().kbnTestServer, + serverArgs: [ + ...baseConfig.getAll().kbnTestServer.serverArgs, + `--xpack.actions.email.services.enabled=${JSON.stringify(emailEnabledServices)}`, + ], + }, + }; +} diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/email.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/email.ts new file mode 100644 index 000000000000..91eeaf5befbf --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/email.ts @@ -0,0 +1,33 @@ +/* + * 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 { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const testSubjects = getService('testSubjects'); + const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); + const find = getService('find'); + + describe('Email - with multiple enabled services config', () => { + beforeEach(async () => { + await pageObjects.common.navigateToApp('triggersActionsConnectors'); + }); + + it('should use the kibana config for enabled services', async () => { + await pageObjects.triggersActionsUI.clickCreateConnectorButton(); + await testSubjects.click('.email-card'); + const emailServicesOptions = await find.allByCssSelector( + '[data-test-subj="emailServiceSelectInput"] > option' + ); + expect(emailServicesOptions.length).to.be(3); + expect(await emailServicesOptions[0].getVisibleText()).to.be(' '); // empty option + expect(await emailServicesOptions[1].getVisibleText()).to.be('Gmail'); + expect(await emailServicesOptions[2].getVisibleText()).to.be('Amazon SES'); + }); + }); +}; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/index.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/index.ts new file mode 100644 index 000000000000..2918bddabb71 --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_email_services_enabled_kbn_config/index.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. + */ + +import type { FtrProviderContext } from '@kbn/test-suites-xpack-platform/alerting_api_integration/common/ftr_provider_context'; +import { + buildUp, + tearDown, +} from '@kbn/test-suites-xpack-platform/alerting_api_integration/spaces_only/tests/helpers'; + +export default function actionsTests({ loadTestFile, getService }: FtrProviderContext) { + describe('Connectors with email services enabled Kibana config', () => { + before(async () => buildUp(getService)); + after(async () => tearDown(getService)); + + loadTestFile(require.resolve('./email')); + }); +}