From 22dd3fbc4555f142ecbaad349027acfb4a7ab78c Mon Sep 17 00:00:00 2001 From: Tre Date: Tue, 9 Apr 2024 14:17:44 +0100 Subject: [PATCH 01/29] =?UTF-8?q?[serverless]=20skip=20"GET=20should=20get?= =?UTF-8?q?=20updated=20labels=20after=20dynamically=20up=E2=80=A6=20(#180?= =?UTF-8?q?352)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary skip "GET should get updated labels after dynamically updating them" for oblt and security suites Details about the failures in https://github.com/elastic/kibana/issues/180348 --- .../test_suites/observability/telemetry/telemetry_config.ts | 4 +++- .../test_suites/security/telemetry/telemetry_config.ts | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/telemetry/telemetry_config.ts b/x-pack/test_serverless/api_integration/test_suites/observability/telemetry/telemetry_config.ts index 78732f6b52826..8fdeb64ac1c19 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/telemetry/telemetry_config.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/telemetry/telemetry_config.ts @@ -12,7 +12,9 @@ export default function telemetryConfigTest({ getService }: FtrProviderContext) const svlCommonApi = getService('svlCommonApi'); const supertest = getService('supertest'); - describe('/api/telemetry/v2/config API Telemetry config', () => { + // failsOnMKI, see https://github.com/elastic/kibana/issues/180348 + describe('/api/telemetry/v2/config API Telemetry config', function () { + this.tags(['failsOnMKI']); const baseConfig = { allowChangingOptInStatus: false, optIn: true, diff --git a/x-pack/test_serverless/api_integration/test_suites/security/telemetry/telemetry_config.ts b/x-pack/test_serverless/api_integration/test_suites/security/telemetry/telemetry_config.ts index 41a02950c4f0f..6701fc93a506a 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/telemetry/telemetry_config.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/telemetry/telemetry_config.ts @@ -12,7 +12,10 @@ export default function telemetryConfigTest({ getService }: FtrProviderContext) const svlCommonApi = getService('svlCommonApi'); const supertest = getService('supertest'); - describe('/api/telemetry/v2/config API Telemetry config', () => { + // failsOnMKI, see https://github.com/elastic/kibana/issues/180348 + describe('/api/telemetry/v2/config API Telemetry config', function () { + this.tags(['failsOnMKI']); + const baseConfig = { allowChangingOptInStatus: false, optIn: true, From f7ebd29b33790115191147c4be65b87c70eb5f54 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Tue, 9 Apr 2024 06:18:08 -0700 Subject: [PATCH 02/29] [Fleet] Add callout when editing an output about plain text secrets being re-saved to secret storage (#180334) ## Summary Resolves #177879. When editing an output we automatically convert any existing plain text secrets to use secrets storage, but this is not at all obvious to the user. This PR adds a callout about the secret being re-saved to use secret storage. This is done for all secrets fields for all output types (Kafka, Logstash, remote ES): image ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../output_form_kafka_authentication.tsx | 10 +++ .../output_form_logstash.tsx | 7 ++ .../output_form_remote_es.tsx | 7 ++ .../output_form_secret_form_row.test.tsx | 23 ++++++ .../output_form_secret_form_row.tsx | 74 +++++++++++++------ 5 files changed, 98 insertions(+), 23 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_authentication.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_authentication.tsx index 5d21567cbbb35..199b92d4de98e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_authentication.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_authentication.tsx @@ -75,6 +75,10 @@ export const OutputFormKafkaAuthentication: React.FunctionComponent<{ onToggleSecretStorage: (secretEnabled: boolean) => void; }> = (props) => { const { inputs, useSecretsStorage, onToggleSecretStorage } = props; + const [isConvertedToSecret, setIsConvertedToSecret] = React.useState({ + kafkaAuthPassword: false, + kafkaSslKey: false, + }); const [isFirstLoad, setIsFirstLoad] = React.useState(true); useEffect(() => { @@ -85,11 +89,13 @@ export const OutputFormKafkaAuthentication: React.FunctionComponent<{ if (inputs.kafkaAuthPasswordInput.value && !inputs.kafkaAuthPasswordSecretInput.value) { inputs.kafkaAuthPasswordSecretInput.setValue(inputs.kafkaAuthPasswordInput.value); inputs.kafkaAuthPasswordInput.clear(); + setIsConvertedToSecret({ ...isConvertedToSecret, kafkaAuthPassword: true }); } if (inputs.kafkaSslKeyInput.value && !inputs.kafkaSslKeySecretInput.value) { inputs.kafkaSslKeySecretInput.setValue(inputs.kafkaSslKeyInput.value); inputs.kafkaSslKeyInput.clear(); + setIsConvertedToSecret({ ...isConvertedToSecret, kafkaSslKey: true }); } } }, [ @@ -100,6 +106,7 @@ export const OutputFormKafkaAuthentication: React.FunctionComponent<{ inputs.kafkaSslKeySecretInput, isFirstLoad, setIsFirstLoad, + isConvertedToSecret, ]); const onToggleSecretAndClearValue = (secretEnabled: boolean) => { @@ -110,6 +117,7 @@ export const OutputFormKafkaAuthentication: React.FunctionComponent<{ inputs.kafkaAuthPasswordSecretInput.setValue(''); inputs.kafkaSslKeySecretInput.setValue(''); } + setIsConvertedToSecret({ kafkaAuthPassword: false, kafkaSslKey: false }); onToggleSecretStorage(secretEnabled); }; @@ -221,6 +229,7 @@ export const OutputFormKafkaAuthentication: React.FunctionComponent<{ )} {...inputs.kafkaSslKeySecretInput.formRowProps} useSecretsStorage={useSecretsStorage} + isConvertedToSecret={isConvertedToSecret.kafkaSslKey} onToggleSecretStorage={onToggleSecretAndClearValue} cancelEdit={inputs.kafkaSslKeySecretInput.cancelEdit} > @@ -291,6 +300,7 @@ export const OutputFormKafkaAuthentication: React.FunctionComponent<{ )} {...inputs.kafkaAuthPasswordSecretInput.formRowProps} useSecretsStorage={useSecretsStorage} + isConvertedToSecret={isConvertedToSecret.kafkaAuthPassword} onToggleSecretStorage={onToggleSecretAndClearValue} cancelEdit={inputs.kafkaAuthPasswordSecretInput.cancelEdit} > diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_logstash.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_logstash.tsx index 9277ee7290937..1884c5aa7551f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_logstash.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_logstash.tsx @@ -32,6 +32,9 @@ export const OutputFormLogstashSection: React.FunctionComponent = (props) const { docLinks } = useStartServices(); const [isFirstLoad, setIsFirstLoad] = React.useState(true); + const [isConvertedToSecret, setIsConvertedToSecret] = React.useState({ + sslKey: false, + }); useEffect(() => { if (!isFirstLoad) return; @@ -41,6 +44,7 @@ export const OutputFormLogstashSection: React.FunctionComponent = (props) if (inputs.sslKeyInput.value && !inputs.sslKeySecretInput.value) { inputs.sslKeySecretInput.setValue(inputs.sslKeyInput.value); inputs.sslKeyInput.clear(); + setIsConvertedToSecret({ ...isConvertedToSecret, sslKey: true }); } } }, [ @@ -49,6 +53,7 @@ export const OutputFormLogstashSection: React.FunctionComponent = (props) inputs.sslKeySecretInput, isFirstLoad, setIsFirstLoad, + isConvertedToSecret, ]); const onToggleSecretAndClearValue = (secretEnabled: boolean) => { @@ -57,6 +62,7 @@ export const OutputFormLogstashSection: React.FunctionComponent = (props) } else { inputs.sslKeySecretInput.setValue(''); } + setIsConvertedToSecret({ sslKey: false }); onToggleSecretStorage(secretEnabled); }; @@ -172,6 +178,7 @@ export const OutputFormLogstashSection: React.FunctionComponent = (props) })} {...inputs.sslKeySecretInput.formRowProps} useSecretsStorage={useSecretsStorage} + isConvertedToSecret={isConvertedToSecret.sslKey} onToggleSecretStorage={onToggleSecretAndClearValue} cancelEdit={inputs.sslKeySecretInput.cancelEdit} > diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_remote_es.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_remote_es.tsx index 1b44bdc97ed8f..354c6ce7d3821 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_remote_es.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_remote_es.tsx @@ -23,6 +23,9 @@ interface Props { export const OutputFormRemoteEsSection: React.FunctionComponent = (props) => { const { inputs, useSecretsStorage, onToggleSecretStorage } = props; + const [isConvertedToSecret, setIsConvertedToSecret] = React.useState({ + serviceToken: false, + }); const [isFirstLoad, setIsFirstLoad] = React.useState(true); @@ -34,6 +37,7 @@ export const OutputFormRemoteEsSection: React.FunctionComponent = (props) if (inputs.serviceTokenInput.value && !inputs.serviceTokenSecretInput.value) { inputs.serviceTokenSecretInput.setValue(inputs.serviceTokenInput.value); inputs.serviceTokenInput.clear(); + setIsConvertedToSecret({ serviceToken: true }); } } }, [ @@ -42,6 +46,7 @@ export const OutputFormRemoteEsSection: React.FunctionComponent = (props) inputs.serviceTokenSecretInput, isFirstLoad, setIsFirstLoad, + isConvertedToSecret, ]); const onToggleSecretAndClearValue = (secretEnabled: boolean) => { @@ -50,6 +55,7 @@ export const OutputFormRemoteEsSection: React.FunctionComponent = (props) } else { inputs.serviceTokenSecretInput.setValue(''); } + setIsConvertedToSecret({ ...isConvertedToSecret, serviceToken: false }); onToggleSecretStorage(secretEnabled); }; @@ -104,6 +110,7 @@ export const OutputFormRemoteEsSection: React.FunctionComponent = (props) {...inputs.serviceTokenSecretInput.formRowProps} cancelEdit={inputs.serviceTokenSecretInput.cancelEdit} useSecretsStorage={useSecretsStorage} + isConvertedToSecret={isConvertedToSecret.serviceToken} onToggleSecretStorage={onToggleSecretAndClearValue} > { expect(onToggleSecretStorage).toHaveBeenCalledWith(true); }); + + it('should display input normally and display a callout when the field is converted to secret storage', () => { + const { getByText, queryByText } = render( + + + + ); + + expect(queryByText('Replace Test Secret')).not.toBeInTheDocument(); + expect( + getByText('This field will be re-saved using secret storage from plain text storage.', { + exact: false, + }) + ).toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_secret_form_row.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_secret_form_row.tsx index 2028c6107bfd3..3b39ecc4dfa2b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_secret_form_row.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_secret_form_row.tsx @@ -7,16 +7,18 @@ import { EuiButtonEmpty, + EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiIcon, + EuiLink, EuiPanel, EuiSpacer, EuiText, EuiToolTip, } from '@elastic/eui'; -import React, { useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; @@ -24,6 +26,7 @@ export const SecretFormRow: React.FC<{ fullWidth?: boolean; children: ConstructorParameters[0]['children']; useSecretsStorage: boolean; + isConvertedToSecret?: boolean; onToggleSecretStorage: (secretEnabled: boolean) => void; error?: string[]; isInvalid?: boolean; @@ -43,10 +46,11 @@ export const SecretFormRow: React.FC<{ onToggleSecretStorage, cancelEdit, useSecretsStorage, + isConvertedToSecret = false, label, }) => { const hasInitialValue = !!initialValue; - const [editMode, setEditMode] = useState(!initialValue); + const [editMode, setEditMode] = useState(isConvertedToSecret || !initialValue); const valueHiddenPanel = ( @@ -101,7 +105,7 @@ export const SecretFormRow: React.FC<{ const editValue = ( <> {children} - {hasInitialValue && ( + {hasInitialValue && !isConvertedToSecret && ( {cancelButton} @@ -110,7 +114,7 @@ export const SecretFormRow: React.FC<{ ); const secretLabel = ( - + <>   {title} @@ -123,25 +127,49 @@ export const SecretFormRow: React.FC<{ > - + ); - const helpText = !initialValue ? ( - onToggleSecretStorage(false)} color="primary" size="xs"> - - - ), - }} - /> - ) : undefined; + const helpText = useMemo(() => { + if (isConvertedToSecret) + return ( + + onToggleSecretStorage(false)} color="primary"> + + + ), + }} + /> + + ); + + if (!initialValue) + return ( + onToggleSecretStorage(false)} color="primary"> + + + ), + }} + /> + ); + return undefined; + }, [initialValue, isConvertedToSecret, onToggleSecretStorage]); const plainTextHelp = ( onToggleSecretStorage(true)} color="primary" size="xs"> + onToggleSecretStorage(true)} color="primary"> - + ), }} /> From c88b3bdc95bbe8164437aa5ea55aeabf607f0566 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 9 Apr 2024 20:18:40 +0700 Subject: [PATCH 03/29] [Fleet] Settings Framework API and UI (#179795) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Follow up on https://github.com/elastic/kibana/pull/170539 Related to https://github.com/elastic/ingest-dev/issues/2471 (Phase 1) Dynamically creating settings fields from configuration. These settings are saved in the agent policy SO's `advanced_settings` field. In the current pr the agent policy read/create/update works including the UI. It still has to be extended to support a few more type of settings: e.g. dropdown values, settings consisting of multiple fields. image These settings are added to the full agent policy agents section: image ## Old description: Add support for saved object mapping and api field name, ## Example API calls and full policy generation Screenshot 2024-04-02 at 3 54 35 PM Screenshot 2024-04-02 at 4 13 42 PM Screenshot 2024-04-02 at 4 13 54 PM Screenshot 2024-04-02 at 5 42 27 PM ## Open questions/Issues ### Saved objects *I think we will still have to do some work to add a new model version when adding a new saved object field, I do not see an easy way to programatically generate that. In a first time it probably could be a manual action to add those migration ### API Open api generation, I think as a first iteration it could be a manual operation to update openAPI spec, but we should be able to programatically generate that with a script in the future --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Julia Bardi <90178898+juliaElastic@users.noreply.github.com> Co-authored-by: Julia Bardi --- .../src/constants.ts | 2 +- .../current_fields.json | 1 + .../current_mappings.json | 4 + .../check_registered_types.test.ts | 2 +- .../fleet/common/experimental_features.ts | 1 + .../plugins/fleet/common/openapi/bundled.json | 5 + .../plugins/fleet/common/openapi/bundled.yaml | 6 + .../components/schemas/agent_policy.yaml | 4 + .../common/settings/agent_policy_settings.ts | 100 +++++++++++ x-pack/plugins/fleet/common/settings/index.ts | 8 + x-pack/plugins/fleet/common/settings/types.ts | 21 +++ .../fleet/common/types/models/agent_policy.ts | 1 + .../components/form_settings/index.test.tsx | 104 ++++++++++++ .../fleet/components/form_settings/index.tsx | 157 ++++++++++++++++++ .../components/agent_policy_form.tsx | 153 ++++++++++++----- .../components/settings/index.tsx | 14 +- .../components/create_agent_policy.tsx | 11 +- .../fleet/server/saved_objects/index.ts | 13 ++ .../agent_policies/full_agent_policy.test.ts | 24 +++ .../agent_policies/full_agent_policy.ts | 11 +- .../form_settings/form_settings.test.ts | 75 +++++++++ .../services/form_settings/form_settings.ts | 105 ++++++++++++ .../server/services/form_settings/index.ts | 12 ++ .../fleet/server/types/models/agent_policy.ts | 2 + x-pack/plugins/fleet/tsconfig.json | 1 + 25 files changed, 785 insertions(+), 52 deletions(-) create mode 100644 x-pack/plugins/fleet/common/settings/agent_policy_settings.ts create mode 100644 x-pack/plugins/fleet/common/settings/index.ts create mode 100644 x-pack/plugins/fleet/common/settings/types.ts create mode 100644 x-pack/plugins/fleet/public/applications/fleet/components/form_settings/index.test.tsx create mode 100644 x-pack/plugins/fleet/public/applications/fleet/components/form_settings/index.tsx create mode 100644 x-pack/plugins/fleet/server/services/form_settings/form_settings.test.ts create mode 100644 x-pack/plugins/fleet/server/services/form_settings/form_settings.ts create mode 100644 x-pack/plugins/fleet/server/services/form_settings/index.ts diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/constants.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/constants.ts index 124515299efc7..0a09032d290e5 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/constants.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/constants.ts @@ -180,7 +180,7 @@ export const HASH_TO_VERSION_MAP = { 'infrastructure-monitoring-log-view|c50526fc6040c5355ed027d34d05b35c': '10.0.0', 'infrastructure-ui-source|3d1b76c39bfb2cc8296b024d73854724': '10.0.0', 'ingest_manager_settings|b91ffb075799c78ffd7dbd51a279c8c9': '10.1.0', - 'ingest-agent-policies|20768dc7ce5eced3eb309e50d8a6cf76': '10.0.0', + 'ingest-agent-policies|0fd93cd11c019b118e93a9157c22057b': '10.1.0', 'ingest-download-sources|0b0f6828e59805bd07a650d80817c342': '10.0.0', 'ingest-outputs|b1237f7fdc0967709e75d65d208ace05': '10.6.0', 'ingest-package-policies|a1a074bad36e68d54f98d2158d60f879': '10.0.0', diff --git a/packages/kbn-check-mappings-update-cli/current_fields.json b/packages/kbn-check-mappings-update-cli/current_fields.json index a66ab72d98aa3..33aace8260291 100644 --- a/packages/kbn-check-mappings-update-cli/current_fields.json +++ b/packages/kbn-check-mappings-update-cli/current_fields.json @@ -471,6 +471,7 @@ ], "infrastructure-ui-source": [], "ingest-agent-policies": [ + "advanced_settings", "agent_features", "agent_features.enabled", "agent_features.name", diff --git a/packages/kbn-check-mappings-update-cli/current_mappings.json b/packages/kbn-check-mappings-update-cli/current_mappings.json index 00d9a5f82fd1c..05e1a48d55d2f 100644 --- a/packages/kbn-check-mappings-update-cli/current_mappings.json +++ b/packages/kbn-check-mappings-update-cli/current_mappings.json @@ -1590,6 +1590,10 @@ }, "ingest-agent-policies": { "properties": { + "advanced_settings": { + "index": false, + "type": "flattened" + }, "agent_features": { "properties": { "enabled": { diff --git a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts index 9a1299b6f1fe4..d2d3761c7ab31 100644 --- a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts +++ b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts @@ -106,7 +106,7 @@ describe('checking migration metadata changes on all registered SO types', () => "infra-custom-dashboards": "1a5994f2e05bb8a1609825ddbf5012f77c5c67f3", "infrastructure-monitoring-log-view": "5f86709d3c27aed7a8379153b08ee5d3d90d77f5", "infrastructure-ui-source": "113182d6895764378dfe7fa9fa027244f3a457c4", - "ingest-agent-policies": "7633e578f60c074f8267bc50ec4763845e431437", + "ingest-agent-policies": "d2ee0bf36a512c2ac744b0def1c822b7880f1f83", "ingest-download-sources": "279a68147e62e4d8858c09ad1cf03bd5551ce58d", "ingest-outputs": "daafff49255ab700e07491376fe89f04fc998b91", "ingest-package-policies": "8a99e165aab00c6c365540427a3abeb7bea03f31", diff --git a/x-pack/plugins/fleet/common/experimental_features.ts b/x-pack/plugins/fleet/common/experimental_features.ts index 48e77dbe1988d..a12711012f307 100644 --- a/x-pack/plugins/fleet/common/experimental_features.ts +++ b/x-pack/plugins/fleet/common/experimental_features.ts @@ -29,6 +29,7 @@ export const allowedExperimentalValues = Object.freeze>( enableStrictKQLValidation: false, subfeaturePrivileges: false, enablePackagesStateMachine: true, + advancedPolicySettings: true, }); type ExperimentalConfigKeys = Array; diff --git a/x-pack/plugins/fleet/common/openapi/bundled.json b/x-pack/plugins/fleet/common/openapi/bundled.json index 1ed749fe31dea..d10af2053ef4e 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.json +++ b/x-pack/plugins/fleet/common/openapi/bundled.json @@ -7383,6 +7383,11 @@ "type": "object", "description": "Override settings that are defined in the agent policy. Input settings cannot be overridden. The override option should be used only in unusual circumstances and not as a routine procedure.", "nullable": true + }, + "advanced_settings": { + "type": "object", + "description": "Advanced settings stored in the agent policy, e.g. agent_limits_go_max_procs", + "nullable": true } }, "required": [ diff --git a/x-pack/plugins/fleet/common/openapi/bundled.yaml b/x-pack/plugins/fleet/common/openapi/bundled.yaml index 03bb90fd84d73..25850c8c6d811 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.yaml +++ b/x-pack/plugins/fleet/common/openapi/bundled.yaml @@ -4734,6 +4734,12 @@ components: settings cannot be overridden. The override option should be used only in unusual circumstances and not as a routine procedure. nullable: true + advanced_settings: + type: object + description: >- + Advanced settings stored in the agent policy, e.g. + agent_limits_go_max_procs + nullable: true required: - id - status diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/agent_policy.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/agent_policy.yaml index 8b088e34c10dc..070d72a5ec353 100644 --- a/x-pack/plugins/fleet/common/openapi/components/schemas/agent_policy.yaml +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/agent_policy.yaml @@ -69,6 +69,10 @@ properties: type: object description: Override settings that are defined in the agent policy. Input settings cannot be overridden. The override option should be used only in unusual circumstances and not as a routine procedure. nullable: true + advanced_settings: + type: object + description: Advanced settings stored in the agent policy, e.g. agent_limits_go_max_procs + nullable: true required: - id - status diff --git a/x-pack/plugins/fleet/common/settings/agent_policy_settings.ts b/x-pack/plugins/fleet/common/settings/agent_policy_settings.ts new file mode 100644 index 0000000000000..7b170d330e650 --- /dev/null +++ b/x-pack/plugins/fleet/common/settings/agent_policy_settings.ts @@ -0,0 +1,100 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { z } from 'zod'; + +import type { SettingsConfig } from './types'; + +export const zodStringWithDurationValidation = z + .string() + .refine((val) => val.match(/^(\d+[s|m|h|d])?$/), { + message: i18n.translate( + 'xpack.fleet.settings.agentPolicyAdvanced.downloadTimeoutValidationMessage', + { + defaultMessage: 'Must be a string with a time unit, e.g. 30s, 5m, 2h, 1d', + } + ), + }); + +export const AGENT_POLICY_ADVANCED_SETTINGS: SettingsConfig[] = [ + { + name: 'agent.limits.go_max_procs', + title: i18n.translate('xpack.fleet.settings.agentPolicyAdvanced.goMaxProcsTitle', { + defaultMessage: 'GO_MAX_PROCS', + }), + description: i18n.translate('xpack.fleet.settings.agentPolicyAdvanced.goMaxProcsDescription', { + defaultMessage: 'Limits the maximum number of CPUs that can be executing simultaneously', + }), + learnMoreLink: + 'https://www.elastic.co/guide/en/fleet/current/enable-custom-policy-settings.html#limit-cpu-usage', + api_field: { + name: 'agent_limits_go_max_procs', + }, + schema: z.number().int().min(0).default(0), + }, + { + name: 'agent.download.timeout', + title: i18n.translate('xpack.fleet.settings.agentPolicyAdvanced.downloadTimeoutTitle', { + defaultMessage: 'Agent binary download timeout', + }), + description: i18n.translate( + 'xpack.fleet.settings.agentPolicyAdvanced.downloadTimeoutDescription', + { + defaultMessage: 'Timeout in seconds for downloading the agent binary', + } + ), + learnMoreLink: + 'https://www.elastic.co/guide/en/fleet/current/enable-custom-policy-settings.html#configure-agent-download-timeout', + api_field: { + name: 'agent_download_timeout', + }, + schema: zodStringWithDurationValidation.default('120s'), + }, + { + name: 'agent.download.target_directory', + api_field: { + name: 'agent_download_target_directory', + }, + title: i18n.translate( + 'xpack.fleet.settings.agentPolicyAdvanced.agentDownloadTargetDirectoryTitle', + { + defaultMessage: 'Agent binary target directory', + } + ), + description: i18n.translate( + 'xpack.fleet.settings.agentPolicyAdvanced.agentDownloadTargetDirectoryDescription', + { + defaultMessage: 'The disk path to which the agent binary will be downloaded', + } + ), + learnMoreLink: + 'https://www.elastic.co/guide/en/fleet/current/elastic-agent-standalone-download.html', + schema: z.string(), + }, + { + name: 'agent.logging.metrics.period', + api_field: { + name: 'agent_logging_metrics_period', + }, + title: i18n.translate( + 'xpack.fleet.settings.agentPolicyAdvanced.agentLoggingMetricsPeriodTitle', + { + defaultMessage: 'Agent logging metrics period', + } + ), + description: i18n.translate( + 'xpack.fleet.settings.agentPolicyAdvanced.agentLoggingMetricsPeriodDescription', + { + defaultMessage: 'The frequency of agent metrics logging', + } + ), + learnMoreLink: + 'https://www.elastic.co/guide/en/fleet/current/elastic-agent-standalone-logging-config.html#elastic-agent-standalone-logging-settings', + schema: zodStringWithDurationValidation.default('30s'), + }, +]; diff --git a/x-pack/plugins/fleet/common/settings/index.ts b/x-pack/plugins/fleet/common/settings/index.ts new file mode 100644 index 0000000000000..b33370b593971 --- /dev/null +++ b/x-pack/plugins/fleet/common/settings/index.ts @@ -0,0 +1,8 @@ +/* + * 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 { AGENT_POLICY_ADVANCED_SETTINGS } from './agent_policy_settings'; diff --git a/x-pack/plugins/fleet/common/settings/types.ts b/x-pack/plugins/fleet/common/settings/types.ts new file mode 100644 index 0000000000000..0fc8ad98f17c0 --- /dev/null +++ b/x-pack/plugins/fleet/common/settings/types.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 { z } from 'zod'; + +export type SettingsSection = 'AGENT_POLICY_ADVANCED_SETTINGS'; + +export interface SettingsConfig { + name: string; + title: string; + description: string; + learnMoreLink?: string; + schema: z.ZodTypeAny; + api_field: { + name: string; + }; +} diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index 4e5d6250208a5..60e635f73f6cc 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -39,6 +39,7 @@ export interface NewAgentPolicy { agent_features?: Array<{ name: string; enabled: boolean }>; is_protected?: boolean; overrides?: { [key: string]: any } | null; + advanced_settings?: { [key: string]: any } | null; } // SO definition for this type is declared in server/types/interfaces diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/form_settings/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/form_settings/index.test.tsx new file mode 100644 index 0000000000000..7d0cb7dbae341 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/components/form_settings/index.test.tsx @@ -0,0 +1,104 @@ +/* + * 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 { act, fireEvent } from '@testing-library/react'; + +import React from 'react'; + +import { z } from 'zod'; + +import { zodStringWithDurationValidation } from '../../../../../common/settings/agent_policy_settings'; +import type { SettingsConfig } from '../../../../../common/settings/types'; +import { createFleetTestRendererMock } from '../../../../mock'; + +import { ConfiguredSettings } from '.'; + +const mockUpdateAgentPolicy = jest.fn(); +const mockUpdateAdvancedSettingsHasErrors = jest.fn(); + +jest.mock('../../sections/agent_policy/components/agent_policy_form', () => ({ + useAgentPolicyFormContext: () => ({ + updateAdvancedSettingsHasErrors: mockUpdateAdvancedSettingsHasErrors, + updateAgentPolicy: mockUpdateAgentPolicy, + agentPolicy: { + advanced_settings: { + agent_limits_go_max_procs: 0, + agent_download_timeout: '120s', + }, + }, + }), +})); + +describe('ConfiguredSettings', () => { + const testRenderer = createFleetTestRendererMock(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + function render(settingsConfig: SettingsConfig[]) { + return testRenderer.render(); + } + + it('should render number field', () => { + const result = render([ + { + name: 'agent.limits.go_max_procs', + title: 'GO_MAX_PROCS', + description: 'Description', + learnMoreLink: '', + api_field: { + name: 'agent_limits_go_max_procs', + }, + schema: z.number().int().min(0).default(0), + }, + ]); + + expect(result.getByText('GO_MAX_PROCS')).not.toBeNull(); + const input = result.getByTestId('configuredSetting-agent.limits.go_max_procs'); + expect(input).toHaveValue(0); + + act(() => { + fireEvent.change(input, { target: { value: '1' } }); + }); + + expect(mockUpdateAgentPolicy).toHaveBeenCalledWith( + expect.objectContaining({ + advanced_settings: expect.objectContaining({ agent_limits_go_max_procs: 1 }), + }) + ); + }); + + it('should render string field with time duration validation', () => { + const result = render([ + { + name: 'agent.download.timeout', + title: 'Agent binary download timeout', + description: 'Description', + learnMoreLink: '', + api_field: { + name: 'agent_download_timeout', + }, + schema: zodStringWithDurationValidation.default('120s'), + }, + ]); + + expect(result.getByText('Agent binary download timeout')).not.toBeNull(); + const input = result.getByTestId('configuredSetting-agent.download.timeout'); + expect(input).toHaveValue('120s'); + + act(() => { + fireEvent.change(input, { target: { value: '120' } }); + }); + + expect(input).toHaveAttribute('aria-invalid', 'true'); + expect( + result.getByText('Must be a string with a time unit, e.g. 30s, 5m, 2h, 1d') + ).not.toBeNull(); + expect(mockUpdateAdvancedSettingsHasErrors).toHaveBeenCalledWith(true); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/form_settings/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/form_settings/index.tsx new file mode 100644 index 0000000000000..03d66d23615ba --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/components/form_settings/index.tsx @@ -0,0 +1,157 @@ +/* + * 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 { z, ZodFirstPartyTypeKind } from 'zod'; +import React, { useState } from 'react'; +import { + EuiDescribedFormGroup, + EuiFieldNumber, + EuiFieldText, + EuiFormRow, + EuiLink, +} from '@elastic/eui'; + +import type { SettingsConfig } from '../../../../../common/settings/types'; +import { useAgentPolicyFormContext } from '../../sections/agent_policy/components/agent_policy_form'; + +export const settingComponentRegistry = new Map< + string, + (settingsconfig: SettingsConfig) => React.ReactElement +>(); + +settingComponentRegistry.set(ZodFirstPartyTypeKind.ZodNumber, (settingsConfig) => { + return ( + ( + + )} + /> + ); +}); + +settingComponentRegistry.set(ZodFirstPartyTypeKind.ZodString, (settingsConfig) => { + return ( + ( + + )} + /> + ); +}); + +const SettingsFieldWrapper: React.FC<{ + settingsConfig: SettingsConfig; + typeName: keyof typeof ZodFirstPartyTypeKind; + renderItem: Function; +}> = ({ settingsConfig, typeName, renderItem }) => { + const [error, setError] = useState(''); + const agentPolicyFormContext = useAgentPolicyFormContext(); + + const fieldKey = `configuredSetting-${settingsConfig.name}`; + const defaultValue: number = + settingsConfig.schema instanceof z.ZodDefault + ? settingsConfig.schema._def.defaultValue() + : undefined; + const coercedSchema = settingsConfig.schema as z.ZodString; + + const convertValue = (value: string, type: keyof typeof ZodFirstPartyTypeKind): any => { + if (type === ZodFirstPartyTypeKind.ZodNumber) { + if (value === '') { + return 0; + } + return parseInt(value, 10); + } + return value; + }; + + const handleChange = (e: React.ChangeEvent) => { + const newValue = convertValue(e.target.value, typeName); + const validationResults = coercedSchema.safeParse(newValue); + + if (!validationResults.success) { + setError(validationResults.error.issues[0].message); + agentPolicyFormContext?.updateAdvancedSettingsHasErrors(true); + } else { + setError(''); + agentPolicyFormContext?.updateAdvancedSettingsHasErrors(false); + } + + const newAdvancedSettings = { + ...(agentPolicyFormContext?.agentPolicy.advanced_settings ?? {}), + [settingsConfig.api_field.name]: newValue, + }; + + agentPolicyFormContext?.updateAgentPolicy({ advanced_settings: newAdvancedSettings }); + }; + + const fieldValue = + agentPolicyFormContext?.agentPolicy.advanced_settings?.[settingsConfig.api_field.name] ?? + defaultValue; + + return ( + {settingsConfig.title}} + description={ + <> + {settingsConfig.description}.{' '} + + Learn more. + + + } + > + + {renderItem({ fieldValue, handleChange, isInvalid: !!error, fieldKey, coercedSchema })} + + + ); +}; + +export function ConfiguredSettings({ + configuredSettings, +}: { + configuredSettings: SettingsConfig[]; +}) { + return ( + <> + {configuredSettings.map((configuredSetting) => { + const Component = settingComponentRegistry.get( + configuredSetting.schema instanceof z.ZodDefault + ? configuredSetting.schema._def.innerType._def.typeName === 'ZodEffects' + ? configuredSetting.schema._def.innerType._def.schema._def.typeName + : configuredSetting.schema._def.innerType._def.typeName + : configuredSetting.schema._def.typeName + ); + + if (!Component) { + throw new Error(`Unknown setting type: ${configuredSetting.schema._type}}`); + } + + return ; + })} + + ); +} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_form.tsx index 230a4152cf55d..8a0d92b159207 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_form.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_form.tsx @@ -12,13 +12,19 @@ import { EuiForm, EuiHorizontalRule, EuiSpacer, + EuiTitle, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import styled from 'styled-components'; +import { AGENT_POLICY_ADVANCED_SETTINGS } from '../../../../../../common/settings'; import type { NewAgentPolicy, AgentPolicy } from '../../../types'; import { useAuthz } from '../../../../../hooks'; +import { ConfiguredSettings } from '../../../components/form_settings'; + +import { ExperimentalFeaturesService } from '../../../../../services'; + import { AgentPolicyAdvancedOptionsContent } from './agent_policy_advanced_fields'; import { AgentPolicyGeneralFields } from './agent_policy_general_fields'; import { AgentPolicyFormSystemMonitoringCheckbox } from './agent_policy_system_monitoring_field'; @@ -37,7 +43,21 @@ interface Props { updateSysMonitoring: (newValue: boolean) => void; validation: ValidationResults; isEditing?: boolean; + // form error state is passed up to the form + updateAdvancedSettingsHasErrors: (hasErrors: boolean) => void; } +const AgentPolicyFormContext = React.createContext< + | { + agentPolicy: Partial & { [key: string]: any }; + updateAgentPolicy: (u: Partial) => void; + updateAdvancedSettingsHasErrors: (hasErrors: boolean) => void; + } + | undefined +>(undefined); + +export const useAgentPolicyFormContext = () => { + return React.useContext(AgentPolicyFormContext); +}; export const AgentPolicyForm: React.FunctionComponent = ({ agentPolicy, @@ -46,10 +66,13 @@ export const AgentPolicyForm: React.FunctionComponent = ({ updateSysMonitoring, validation, isEditing = false, + updateAdvancedSettingsHasErrors, }) => { const authz = useAuthz(); const disabled = !authz.fleet.allAgents; + const { advancedPolicySettings } = ExperimentalFeaturesService.get(); + const generalSettingsWrapper = (children: JSX.Element[]) => ( = ({ ); return ( - - {!isEditing ? ( - - ) : ( - generalSettingsWrapper([ + + + {!isEditing ? ( , - ]) - )} - {!isEditing ? ( - - ) : null} - {!isEditing ? ( - <> - - - + ) : ( + generalSettingsWrapper([ + , + ]) + )} + {!isEditing ? ( + + ) : null} + {!isEditing ? ( + <> + + + + } + buttonClassName="ingest-active-button" + > + + - } - buttonClassName="ingest-active-button" - > - + + {advancedPolicySettings ? ( + <> + + + +

+ +

+
+ + + + ) : null} +
+ + ) : ( + <> -
- - ) : ( - - )} -
+ {advancedPolicySettings ? ( + <> + + + +

+ +

+
+ + + + ) : null} + + + )} +
+ ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx index b3559fb876e1f..f9ca5fa24226c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx @@ -52,6 +52,7 @@ const pickAgentPolicyKeysToSend = (agentPolicy: AgentPolicy) => 'fleet_server_host_id', 'agent_features', 'is_protected', + 'advanced_settings', ]); const FormWrapper = styled.div` @@ -77,6 +78,7 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( const [agentCount, setAgentCount] = useState(0); const [withSysMonitoring, setWithSysMonitoring] = useState(true); const validation = agentPolicyFormValidation(agentPolicy); + const [hasAdvancedSettingsErrors, setHasAdvancedSettingsErrors] = useState(false); const updateAgentPolicy = (updatedFields: Partial) => { setAgentPolicy({ @@ -169,6 +171,7 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( updateSysMonitoring={(newValue) => setWithSysMonitoring(newValue)} validation={validation} isEditing={true} + updateAdvancedSettingsHasErrors={setHasAdvancedSettingsErrors} /> {hasChanges ? ( @@ -202,7 +205,11 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( {showDevtoolsRequest ? ( 0} + isDisabled={ + isLoading || + Object.keys(validation).length > 0 || + hasAdvancedSettingsErrors + } btnProps={{ color: 'text', }} @@ -221,7 +228,10 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( onClick={onSubmit} isLoading={isLoading} isDisabled={ - !hasFleetAllPrivileges || isLoading || Object.keys(validation).length > 0 + !hasFleetAllPrivileges || + isLoading || + Object.keys(validation).length > 0 || + hasAdvancedSettingsErrors } iconType="save" color="primary" diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/components/create_agent_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/components/create_agent_policy.tsx index 09650bafdff3c..bfe9d233b2bf4 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/components/create_agent_policy.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/components/create_agent_policy.tsx @@ -53,6 +53,7 @@ export const CreateAgentPolicyFlyout: React.FunctionComponent = ({ const [isLoading, setIsLoading] = useState(false); const [withSysMonitoring, setWithSysMonitoring] = useState(true); const validation = agentPolicyFormValidation(agentPolicy); + const [hasAdvancedSettingsErrors, setHasAdvancedSettingsErrors] = useState(false); const updateAgentPolicy = (updatedFields: Partial) => { setAgentPolicy({ @@ -95,6 +96,7 @@ export const CreateAgentPolicyFlyout: React.FunctionComponent = ({ withSysMonitoring={withSysMonitoring} updateSysMonitoring={(newValue) => setWithSysMonitoring(newValue)} validation={validation} + updateAdvancedSettingsHasErrors={setHasAdvancedSettingsErrors} /> ); @@ -120,7 +122,9 @@ export const CreateAgentPolicyFlyout: React.FunctionComponent = ({ {showDevtoolsRequest ? ( 0} + isDisabled={ + isLoading || Object.keys(validation).length > 0 || hasAdvancedSettingsErrors + } description={i18n.translate( 'xpack.fleet.createAgentPolicy.devtoolsRequestDescription', { @@ -136,7 +140,10 @@ export const CreateAgentPolicyFlyout: React.FunctionComponent = ({ fill isLoading={isLoading} isDisabled={ - !hasFleetAllPrivileges || isLoading || Object.keys(validation).length > 0 + !hasFleetAllPrivileges || + isLoading || + Object.keys(validation).length > 0 || + hasAdvancedSettingsErrors } onClick={async () => { setIsLoading(true); diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index 4aef23990ffec..363b26be84a47 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -156,6 +156,7 @@ export const getSavedObjectTypes = (): { [key: string]: SavedObjectsType } => ({ is_protected: { type: 'boolean' }, overrides: { type: 'flattened', index: false }, keep_monitoring_alive: { type: 'boolean' }, + advanced_settings: { type: 'flattened', index: false }, }, }, migrations: { @@ -165,6 +166,18 @@ export const getSavedObjectTypes = (): { [key: string]: SavedObjectsType } => ({ '8.5.0': migrateAgentPolicyToV850, '8.9.0': migrateAgentPolicyToV890, }, + modelVersions: { + '1': { + changes: [ + { + type: 'mappings_addition', + addedMappings: { + advanced_settings: { type: 'flattened', index: false }, + }, + }, + ], + }, + }, }, [OUTPUT_SAVED_OBJECT_TYPE]: { name: OUTPUT_SAVED_OBJECT_TYPE, diff --git a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts index 0ecd385c2516c..7f203dd139954 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts @@ -714,6 +714,30 @@ describe('getFullAgentPolicy', () => { revision: 1, }); }); + + it('should return a policy with advanced settings', async () => { + mockAgentPolicy({ + advanced_settings: { + agent_limits_go_max_procs: 2, + agent_download_timeout: '60s', + agent_download_target_directory: '/tmp', + agent_logging_metrics_period: '10s', + }, + }); + const agentPolicy = await getFullAgentPolicy(savedObjectsClientMock.create(), 'agent-policy'); + + expect(agentPolicy).toMatchObject({ + id: 'agent-policy', + agent: { + download: { + timeout: '60s', + target_directory: '/tmp', + }, + limits: { go_max_procs: 2 }, + logging: { metrics: { period: '10s' } }, + }, + }); + }); }); describe('transformOutputToFullPolicyOutput', () => { diff --git a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts index ab277a97774d0..bec47eea524c4 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts @@ -10,6 +10,7 @@ import type { SavedObjectsClientContract } from '@kbn/core/server'; import { safeLoad } from 'js-yaml'; import deepMerge from 'deepmerge'; +import { set } from '@kbn/safer-lodash-set'; import { getDefaultPresetForEsOutput, @@ -37,7 +38,7 @@ import { kafkaCompressionType, outputType, } from '../../../common/constants'; - +import { getSettingsValuesForAgentPolicy } from '../form_settings'; import { getPackageInfo } from '../epm/packages'; import { pkgToPkgKey, splitPkgKey } from '../epm/registry'; import { appContextService } from '../app_context'; @@ -242,6 +243,14 @@ export async function getFullAgentPolicy( fullAgentPolicy.fleet = generateFleetConfig(fleetServerHosts, proxies); } + const settingsValues = getSettingsValuesForAgentPolicy( + 'AGENT_POLICY_ADVANCED_SETTINGS', + agentPolicy + ); + Object.entries(settingsValues).forEach(([settingsKey, settingValue]) => { + set(fullAgentPolicy, settingsKey, settingValue); + }); + // populate protection and signed properties const messageSigningService = appContextService.getMessageSigningService(); if (messageSigningService && fullAgentPolicy.agent) { diff --git a/x-pack/plugins/fleet/server/services/form_settings/form_settings.test.ts b/x-pack/plugins/fleet/server/services/form_settings/form_settings.test.ts new file mode 100644 index 0000000000000..d620737e8dc27 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/form_settings/form_settings.test.ts @@ -0,0 +1,75 @@ +/* + * 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 { z } from 'zod'; +import { schema } from '@kbn/config-schema'; + +import type { SettingsConfig } from '../../../common/settings/types'; + +import { _getSettingsAPISchema, _getSettingsValuesForAgentPolicy } from './form_settings'; + +const TEST_SETTINGS: SettingsConfig[] = [ + { + name: 'test.foo', + title: 'test', + description: 'test', + schema: z.boolean(), + api_field: { + name: 'test_foo', + }, + }, + { + name: 'test.foo.default_value', + title: 'test', + description: 'test', + schema: z.string().default('test'), + api_field: { + name: 'test_foo_default_value', + }, + }, +]; + +describe('form_settings', () => { + describe('_getSettingsAPISchema', () => { + it('generate a valid API schema for api_field', () => { + const apiSchema = schema.object(_getSettingsAPISchema(TEST_SETTINGS)); + + expect(() => + apiSchema.validate({ + advanced_settings: { + test_foo: 'not valid', + }, + }) + ).toThrowError(/Expected boolean, received string/); + + expect(() => + apiSchema.validate({ + advanced_settings: { + test_foo: true, + }, + }) + ).not.toThrow(); + }); + + it('generate a valid API schema for api_field with default value', () => { + const apiSchema = schema.object(_getSettingsAPISchema(TEST_SETTINGS)); + const res = apiSchema.validate({ advanced_settings: {} }); + expect(res).toEqual({ advanced_settings: { test_foo_default_value: 'test' } }); + }); + }); + + describe('_getSettingsValuesForAgentPolicy', () => { + it('generate the proper values for agent policy (full agent policy)', () => { + const res = _getSettingsValuesForAgentPolicy(TEST_SETTINGS, { + advanced_settings: { + test_foo_default_value: 'test', + }, + } as any); + expect(res).toEqual({ 'test.foo.default_value': 'test' }); + }); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/form_settings/form_settings.ts b/x-pack/plugins/fleet/server/services/form_settings/form_settings.ts new file mode 100644 index 0000000000000..a381fcd55b4ba --- /dev/null +++ b/x-pack/plugins/fleet/server/services/form_settings/form_settings.ts @@ -0,0 +1,105 @@ +/* + * 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 Props, schema } from '@kbn/config-schema'; +import { stringifyZodError } from '@kbn/zod-helpers'; + +import type { SettingsConfig, SettingsSection } from '../../../common/settings/types'; +import { AGENT_POLICY_ADVANCED_SETTINGS } from '../../../common/settings'; +import type { AgentPolicy } from '../../types'; + +export function getSettingsAPISchema(settingSection: SettingsSection) { + const settings = getSettings(settingSection); + + return _getSettingsAPISchema(settings); +} + +export function _getSettingsAPISchema(settings: SettingsConfig[]): Props { + const validations: Props = {}; + settings.forEach((setting) => { + if (!setting.api_field) { + return; + } + const defaultValueRes = setting.schema.safeParse(undefined); + const defaultValue = defaultValueRes.success ? defaultValueRes.data : undefined; + if (defaultValue) { + validations[setting.api_field.name] = schema.oneOf( + [ + schema.any({ + validate: (val: any) => { + const res = setting.schema.safeParse(val); + if (!res.success) { + return stringifyZodError(res.error); + } + }, + }), + schema.literal(null), + ], + { + defaultValue, + } + ); + } else { + validations[setting.api_field.name] = schema.maybe( + schema.nullable( + schema.any({ + validate: (val: any) => { + const res = setting.schema.safeParse(val); + if (!res.success) { + return stringifyZodError(res.error); + } + }, + }) + ) + ); + } + }); + + const advancedSettingsValidations: Props = { + advanced_settings: schema.maybe( + schema.object({ + ...validations, + }) + ), + }; + return advancedSettingsValidations; +} + +export function getSettingsValuesForAgentPolicy( + settingSection: SettingsSection, + agentPolicy: AgentPolicy +) { + const settings = getSettings(settingSection); + + return _getSettingsValuesForAgentPolicy(settings, agentPolicy); +} + +export function _getSettingsValuesForAgentPolicy( + settings: SettingsConfig[], + agentPolicy: AgentPolicy +) { + const settingsValues: { [k: string]: any } = {}; + settings.forEach((setting) => { + if (!setting.api_field) { + return; + } + + const val = agentPolicy.advanced_settings?.[setting.api_field.name]; + if (val) { + settingsValues[setting.name] = val; + } + }); + return settingsValues; +} + +export function getSettings(settingSection: SettingsSection) { + if (settingSection === 'AGENT_POLICY_ADVANCED_SETTINGS') { + return AGENT_POLICY_ADVANCED_SETTINGS; + } + + throw new Error(`Invalid settings section ${settingSection}`); +} diff --git a/x-pack/plugins/fleet/server/services/form_settings/index.ts b/x-pack/plugins/fleet/server/services/form_settings/index.ts new file mode 100644 index 0000000000000..b88cd1e0eda2a --- /dev/null +++ b/x-pack/plugins/fleet/server/services/form_settings/index.ts @@ -0,0 +1,12 @@ +/* + * 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 { + getSettings, + getSettingsAPISchema, + getSettingsValuesForAgentPolicy, +} from './form_settings'; diff --git a/x-pack/plugins/fleet/server/types/models/agent_policy.ts b/x-pack/plugins/fleet/server/types/models/agent_policy.ts index 518510f0b8454..748a5c81c1bfb 100644 --- a/x-pack/plugins/fleet/server/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/server/types/models/agent_policy.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { agentPolicyStatuses, dataTypes } from '../../../common/constants'; import { isValidNamespace } from '../../../common/services'; +import { getSettingsAPISchema } from '../../services/form_settings'; import { PackagePolicySchema } from './package_policy'; @@ -81,6 +82,7 @@ export const AgentPolicyBaseSchema = { }) ) ), + ...getSettingsAPISchema('AGENT_POLICY_ADVANCED_SETTINGS'), }; export const NewAgentPolicySchema = schema.object({ diff --git a/x-pack/plugins/fleet/tsconfig.json b/x-pack/plugins/fleet/tsconfig.json index b99fb0cce0985..d57c36aa70165 100644 --- a/x-pack/plugins/fleet/tsconfig.json +++ b/x-pack/plugins/fleet/tsconfig.json @@ -105,5 +105,6 @@ "@kbn/core-http-server-mocks", "@kbn/code-editor", "@kbn/core-test-helpers-model-versions", + "@kbn/zod-helpers", ] } From 737156f24d64e05292cc0e273dd04cb9db3a0307 Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 9 Apr 2024 08:19:40 -0500 Subject: [PATCH 04/29] [ci] Upgrade follow-redirects to 1.15.6 (#180326) --- .buildkite/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.buildkite/package-lock.json b/.buildkite/package-lock.json index 401f25347ebc0..b782b9c1d34eb 100644 --- a/.buildkite/package-lock.json +++ b/.buildkite/package-lock.json @@ -696,9 +696,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -2200,9 +2200,9 @@ "dev": true }, "follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==" + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" }, "form-data": { "version": "4.0.0", From 8a211291204d9140aa7546a2b68797d02a52bbcc Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Tue, 9 Apr 2024 08:30:58 -0500 Subject: [PATCH 05/29] Add APM OpenAPI spec (#180096) Add a YAML OpenAPI spec for some of the [APM APIs](https://www.elastic.co/guide/en/kibana/current/apm-api.html). This spec was artisanally crafted by @sorenlouv and previously published https://gist.github.com/sorenlouv/19fb1ffc0b7552fb41b193462d6ee9db. It has been copied here to fulfill some requirements for https://github.com/elastic/docs-projects/issues/175. We will prioritize the existing issue https://github.com/elastic/kibana/issues/129061 to replace the contents with automatically-generated and complete specs. --- .../apm/docs/openapi/apm.yaml | 169 ++++++++++++++++++ .../apm/docs/openapi/apm/README.md | 17 ++ 2 files changed, 186 insertions(+) create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml create mode 100644 x-pack/plugins/observability_solution/apm/docs/openapi/apm/README.md diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml b/x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml new file mode 100644 index 0000000000000..c110abbfafa92 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml @@ -0,0 +1,169 @@ +openapi: 3.0.0 +info: + title: APM UI + version: 1.0.0 +paths: + /api/apm/agent_keys: + post: + summary: Create an APM agent key + description: Create a new agent key for APM. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + privileges: + type: array + items: + type: string + enum: + - event:write + - config_agent:read + responses: + "200": + description: Agent key created successfully + content: + application/json: + schema: + type: object + properties: + api_key: + type: string + expiration: + type: integer + format: int64 + id: + type: string + name: + type: string + encoded: + type: string + /api/apm/services/{serviceName}/annotation/search: + get: + summary: Search for annotations + description: Search for annotations related to a specific service. + parameters: + - name: serviceName + in: path + required: true + description: The name of the service + schema: + type: string + - name: environment + in: query + required: false + description: The environment to filter annotations by + schema: + type: string + - name: start + in: query + required: false + description: The start date for the search + schema: + type: string + - name: end + in: query + required: false + description: The end date for the search + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + schema: + type: object + properties: + annotations: + type: array + items: + type: object + properties: + type: + type: string + enum: + - version + id: + type: string + "@timestamp": + type: number + text: + type: string + /api/apm/services/{serviceName}/annotation: + post: + summary: Create a service annotation + description: Create a new annotation for a specific service. + parameters: + - name: serviceName + in: path + required: true + description: The name of the service + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + '@timestamp': + type: string + service: + type: object + properties: + version: + type: string + environment: + type: string + message: + type: string + tags: + type: array + items: + type: string + + responses: + '200': + description: Annotation created successfully + content: + application/json: + schema: + type: object + properties: + _id: + type: string + _index: + type: string + _source: + type: object + properties: + annotation: + type: string + tags: + type: array + items: + type: string + message: + type: string + service: + type: object + properties: + name: + type: string + environment: + type: string + version: + type: string + event: + type: object + properties: + created: + type: string + '@timestamp': + type: string diff --git a/x-pack/plugins/observability_solution/apm/docs/openapi/apm/README.md b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/README.md new file mode 100644 index 0000000000000..da35d6b891239 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/docs/openapi/apm/README.md @@ -0,0 +1,17 @@ +# APM app OpenAPI documentation + +This directory contains [OpenAPI specifications](https://swagger.io/specification/) for the [APM app API](https://www.elastic.co/guide/en/kibana/current/apm-api.html) in Kibana. + +Included: + +* [Agent Configuration API](https://www.elastic.co/guide/en/kibana/current/agent-config-api.html) +* [Annotation API](https://www.elastic.co/guide/en/kibana/current/apm-annotation-api.html) + +Not included: + +* [APM agent Key API](https://www.elastic.co/guide/en/kibana/current/agent-key-api.html) +* [RUM source map API](https://www.elastic.co/guide/en/kibana/current/rum-sourcemap-api.html) + +The specifications for the included APIs are in the apm.yaml file in this directory. + +These specifications are manually written. The missing ones will be included in the future. From 051b32c49b4796606f65d3a84d89e935d1e1eb2a Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 9 Apr 2024 09:55:46 -0400 Subject: [PATCH 06/29] skip failing test suite (#171168) --- .../cypress/e2e/artifacts/artifacts_mocked_data.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts index 8d21ff3804364..d1b724acad6ef 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts @@ -32,7 +32,8 @@ const loginWithoutAccess = (url: string) => { }; // Flaky: https://github.com/elastic/kibana/issues/171168 -describe('Artifacts pages', { tags: ['@ess', '@serverless'] }, () => { +// Failing: See https://github.com/elastic/kibana/issues/171168 +describe.skip('Artifacts pages', { tags: ['@ess', '@serverless'] }, () => { let endpointData: ReturnTypeFromChainable | undefined; before(() => { From 57fa1a024f611b623f02a85f235536b10ef7ff30 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 9 Apr 2024 09:56:04 -0400 Subject: [PATCH 07/29] skip failing test suite (#171643) --- ...dpoint_list_with_security_essentials.cy.ts | 63 +++++++++---------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts index 9cd298535df26..e8ea8d5ae1d70 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts @@ -15,45 +15,42 @@ import { visitEndpointList, } from '../../screens'; -describe( - 'When on the Endpoint List in Security Essentials PLI', - { - tags: ['@serverless'], - env: { - ftrConfig: { - productTypes: [{ product_line: 'security', product_tier: 'essentials' }], - }, +// Failing: See https://github.com/elastic/kibana/issues/171643 +describe.skip('When on the Endpoint List in Security Essentials PLI', { + tags: ['@serverless'], + env: { + ftrConfig: { + productTypes: [{ product_line: 'security', product_tier: 'essentials' }], }, }, - () => { - describe('and Isolated hosts exist', () => { - let indexedEndpointData: CyIndexEndpointHosts; +}, () => { + describe('and Isolated hosts exist', () => { + let indexedEndpointData: CyIndexEndpointHosts; - before(() => { - indexEndpointHosts({ isolation: true }).then((response) => { - indexedEndpointData = response; - }); + before(() => { + indexEndpointHosts({ isolation: true }).then((response) => { + indexedEndpointData = response; }); + }); - after(() => { - if (indexedEndpointData) { - indexedEndpointData.cleanup(); - } - }); + after(() => { + if (indexedEndpointData) { + indexedEndpointData.cleanup(); + } + }); - beforeEach(() => { - login(); - visitEndpointList(); - openRowActionMenu(); - }); + beforeEach(() => { + login(); + visitEndpointList(); + openRowActionMenu(); + }); - it('should display `release` options in host row actions', () => { - getUnIsolateActionMenuItem().should('exist'); - }); + it('should display `release` options in host row actions', () => { + getUnIsolateActionMenuItem().should('exist'); + }); - it('should NOT display access to response console', () => { - getConsoleActionMenuItem().should('not.exist'); - }); + it('should NOT display access to response console', () => { + getConsoleActionMenuItem().should('not.exist'); }); - } -); + }); +}); From 70732768d68089a011f1273ace424cdde2e1660a Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 9 Apr 2024 09:56:12 -0400 Subject: [PATCH 08/29] skip failing test suite (#170985) --- .../essentials_with_endpoint.roles.cy.ts | 365 +++++++++--------- 1 file changed, 181 insertions(+), 184 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts index 4e0ae2080a97b..41b2f00dd9b41 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts @@ -23,182 +23,224 @@ import { ensurePolicyDetailsPageAuthzAccess, } from '../../../screens'; -describe( - 'Roles for Security Essential PLI with Endpoint Essentials addon', - { - tags: ['@serverless'], - env: { - ftrConfig: { - productTypes: [ - { product_line: 'security', product_tier: 'essentials' }, - { product_line: 'endpoint', product_tier: 'essentials' }, - ], - }, +// Failing: See https://github.com/elastic/kibana/issues/170985 +describe.skip('Roles for Security Essential PLI with Endpoint Essentials addon', { + tags: ['@serverless'], + env: { + ftrConfig: { + productTypes: [ + { product_line: 'security', product_tier: 'essentials' }, + { product_line: 'endpoint', product_tier: 'essentials' }, + ], }, }, - () => { - const allPages = getEndpointManagementPageList(); - const pageById = getEndpointManagementPageMap(); +}, () => { + const allPages = getEndpointManagementPageList(); + const pageById = getEndpointManagementPageMap(); - let loadedEndpoints: CyIndexEndpointHosts; + let loadedEndpoints: CyIndexEndpointHosts; - before(() => { - indexEndpointHosts().then((response) => { - loadedEndpoints = response; - }); - }); - - after(() => { - if (loadedEndpoints) { - loadedEndpoints.cleanup(); - } + before(() => { + indexEndpointHosts().then((response) => { + loadedEndpoints = response; }); + }); - // roles `t1_analyst` and `t2_analyst` are the same as far as endpoint access - [ROLE.t1_analyst, ROLE.t2_analyst].forEach((roleName) => { - describe(`for role: ${roleName}`, () => { - const deniedPages = allPages.filter((page) => page.id !== 'endpointList'); - - beforeEach(() => { - login(roleName); - }); - - it('should have READ access to Endpoint list page', () => { - ensureEndpointListPageAuthzAccess('read', true); - }); + after(() => { + if (loadedEndpoints) { + loadedEndpoints.cleanup(); + } + }); - for (const { url, title } of deniedPages) { - it(`should NOT have access to: ${title}`, () => { - cy.visit(url); - getNoPrivilegesPage().should('exist'); - }); - } - - it('should NOT have access to Fleet', () => { - visitFleetAgentList(); - ensureFleetPermissionDeniedScreen(); - }); - }); - }); - - describe('for role: t3_analyst', () => { - const artifactPagesFullAccess = [ - pageById.trustedApps, - pageById.eventFilters, - pageById.blocklist, - ]; + // roles `t1_analyst` and `t2_analyst` are the same as far as endpoint access + [ROLE.t1_analyst, ROLE.t2_analyst].forEach((roleName) => { + describe(`for role: ${roleName}`, () => { + const deniedPages = allPages.filter((page) => page.id !== 'endpointList'); beforeEach(() => { - login(ROLE.t3_analyst); + login(roleName); }); - it('should have access to Endpoint list page', () => { - ensureEndpointListPageAuthzAccess('all', true); - }); - - it('should have read access to Endpoint Policy Management', () => { - ensurePolicyListPageAuthzAccess('read', true); - ensurePolicyDetailsPageAuthzAccess( - loadedEndpoints.data.integrationPolicies[0].id, - 'read', - true - ); + it('should have READ access to Endpoint list page', () => { + ensureEndpointListPageAuthzAccess('read', true); }); - for (const { title, id } of artifactPagesFullAccess) { - it(`should have CRUD access to: ${title}`, () => { - ensureArtifactPageAuthzAccess('all', id as EndpointArtifactPageId); + for (const { url, title } of deniedPages) { + it(`should NOT have access to: ${title}`, () => { + cy.visit(url); + getNoPrivilegesPage().should('exist'); }); } - it(`should NOT have access to Host Isolation Exceptions`, () => { - ensureArtifactPageAuthzAccess( - 'none', - pageById.hostIsolationExceptions.id as EndpointArtifactPageId - ); - }); - it('should NOT have access to Fleet', () => { visitFleetAgentList(); ensureFleetPermissionDeniedScreen(); }); }); + }); - describe('for role: threat_intelligence_analyst', () => { - const deniedPages = allPages.filter(({ id }) => id !== 'blocklist' && id !== 'endpointList'); + describe('for role: t3_analyst', () => { + const artifactPagesFullAccess = [ + pageById.trustedApps, + pageById.eventFilters, + pageById.blocklist, + ]; - beforeEach(() => { - login(ROLE.threat_intelligence_analyst); - }); + beforeEach(() => { + login(ROLE.t3_analyst); + }); - it('should have access to Endpoint list page', () => { - ensureEndpointListPageAuthzAccess('read', true); - }); + it('should have access to Endpoint list page', () => { + ensureEndpointListPageAuthzAccess('all', true); + }); - it(`should have ALL access to: Blocklist`, () => { - cy.visit(pageById.blocklist.url); - getArtifactListEmptyStateAddButton(pageById.blocklist.id as EndpointArtifactPageId).should( - 'exist' - ); + it('should have read access to Endpoint Policy Management', () => { + ensurePolicyListPageAuthzAccess('read', true); + ensurePolicyDetailsPageAuthzAccess( + loadedEndpoints.data.integrationPolicies[0].id, + 'read', + true + ); + }); + + for (const { title, id } of artifactPagesFullAccess) { + it(`should have CRUD access to: ${title}`, () => { + ensureArtifactPageAuthzAccess('all', id as EndpointArtifactPageId); }); + } - for (const { url, title } of deniedPages) { - it(`should NOT have access to: ${title}`, () => { - cy.visit(url); - getNoPrivilegesPage().should('exist'); - }); - } + it(`should NOT have access to Host Isolation Exceptions`, () => { + ensureArtifactPageAuthzAccess( + 'none', + pageById.hostIsolationExceptions.id as EndpointArtifactPageId + ); + }); - it('should NOT have access to Fleet', () => { - visitFleetAgentList(); - ensureFleetPermissionDeniedScreen(); - }); + it('should NOT have access to Fleet', () => { + visitFleetAgentList(); + ensureFleetPermissionDeniedScreen(); }); + }); - describe('for role: rule_author', () => { - const artifactPagesFullAccess = [ - pageById.trustedApps, - pageById.eventFilters, - pageById.blocklist, - ]; + describe('for role: threat_intelligence_analyst', () => { + const deniedPages = allPages.filter(({ id }) => id !== 'blocklist' && id !== 'endpointList'); - beforeEach(() => { - login(ROLE.rule_author); - }); + beforeEach(() => { + login(ROLE.threat_intelligence_analyst); + }); - for (const { id, title } of artifactPagesFullAccess) { - it(`should have CRUD access to: ${title}`, () => { - ensureArtifactPageAuthzAccess('all', id as EndpointArtifactPageId); - }); - } + it('should have access to Endpoint list page', () => { + ensureEndpointListPageAuthzAccess('read', true); + }); + + it(`should have ALL access to: Blocklist`, () => { + cy.visit(pageById.blocklist.url); + getArtifactListEmptyStateAddButton(pageById.blocklist.id as EndpointArtifactPageId).should( + 'exist' + ); + }); - it('should have access to Endpoint list page', () => { - ensureEndpointListPageAuthzAccess('all', true); + for (const { url, title } of deniedPages) { + it(`should NOT have access to: ${title}`, () => { + cy.visit(url); + getNoPrivilegesPage().should('exist'); }); + } - it('should have access to policy management', () => { - ensurePolicyListPageAuthzAccess('all', true); - ensurePolicyDetailsPageAuthzAccess( - loadedEndpoints.data.integrationPolicies[0].id, - 'all', - true - ); + it('should NOT have access to Fleet', () => { + visitFleetAgentList(); + ensureFleetPermissionDeniedScreen(); + }); + }); + + describe('for role: rule_author', () => { + const artifactPagesFullAccess = [ + pageById.trustedApps, + pageById.eventFilters, + pageById.blocklist, + ]; + + beforeEach(() => { + login(ROLE.rule_author); + }); + + for (const { id, title } of artifactPagesFullAccess) { + it(`should have CRUD access to: ${title}`, () => { + ensureArtifactPageAuthzAccess('all', id as EndpointArtifactPageId); }); + } - it(`should NOT have access to Host Isolation Exceptions`, () => { - ensureArtifactPageAuthzAccess( - 'none', - pageById.hostIsolationExceptions.id as EndpointArtifactPageId - ); + it('should have access to Endpoint list page', () => { + ensureEndpointListPageAuthzAccess('all', true); + }); + + it('should have access to policy management', () => { + ensurePolicyListPageAuthzAccess('all', true); + ensurePolicyDetailsPageAuthzAccess( + loadedEndpoints.data.integrationPolicies[0].id, + 'all', + true + ); + }); + + it(`should NOT have access to Host Isolation Exceptions`, () => { + ensureArtifactPageAuthzAccess( + 'none', + pageById.hostIsolationExceptions.id as EndpointArtifactPageId + ); + }); + + it('should NOT have access to Fleet', () => { + visitFleetAgentList(); + ensureFleetPermissionDeniedScreen(); + }); + }); + + describe('for role: soc_manager', () => { + const artifactPagesFullAccess = [ + pageById.trustedApps, + pageById.eventFilters, + pageById.blocklist, + ]; + const grantedAccessPages = [pageById.endpointList, pageById.policyList]; + + beforeEach(() => { + login(ROLE.soc_manager); + }); + + for (const { id, title } of artifactPagesFullAccess) { + it(`should have CRUD access to: ${title}`, () => { + ensureArtifactPageAuthzAccess('all', id as EndpointArtifactPageId); }); + } - it('should NOT have access to Fleet', () => { - visitFleetAgentList(); - ensureFleetPermissionDeniedScreen(); + for (const { url, title } of grantedAccessPages) { + it(`should have access to: ${title}`, () => { + cy.visit(url); + getNoPrivilegesPage().should('not.exist'); }); + } + + it(`should NOT have access to Host Isolation Exceptions`, () => { + ensureArtifactPageAuthzAccess( + 'none', + pageById.hostIsolationExceptions.id as EndpointArtifactPageId + ); }); - describe('for role: soc_manager', () => { + it('should NOT have access to Fleet', () => { + visitFleetAgentList(); + ensureFleetPermissionDeniedScreen(); + }); + }); + + // Endpoint Operations Manager, Endpoint Policy Manager and Platform Engineer currently have the same level of access + [ + ROLE.platform_engineer, + ROLE.endpoint_operations_analyst, + ROLE.endpoint_policy_manager, + ].forEach((roleName) => { + describe(`for role: ${roleName}`, () => { const artifactPagesFullAccess = [ pageById.trustedApps, pageById.eventFilters, @@ -207,7 +249,7 @@ describe( const grantedAccessPages = [pageById.endpointList, pageById.policyList]; beforeEach(() => { - login(ROLE.soc_manager); + login(roleName); }); for (const { id, title } of artifactPagesFullAccess) { @@ -230,55 +272,10 @@ describe( ); }); - it('should NOT have access to Fleet', () => { + it('should have access to Fleet', () => { visitFleetAgentList(); - ensureFleetPermissionDeniedScreen(); - }); - }); - - // Endpoint Operations Manager, Endpoint Policy Manager and Platform Engineer currently have the same level of access - [ - ROLE.platform_engineer, - ROLE.endpoint_operations_analyst, - ROLE.endpoint_policy_manager, - ].forEach((roleName) => { - describe(`for role: ${roleName}`, () => { - const artifactPagesFullAccess = [ - pageById.trustedApps, - pageById.eventFilters, - pageById.blocklist, - ]; - const grantedAccessPages = [pageById.endpointList, pageById.policyList]; - - beforeEach(() => { - login(roleName); - }); - - for (const { id, title } of artifactPagesFullAccess) { - it(`should have CRUD access to: ${title}`, () => { - ensureArtifactPageAuthzAccess('all', id as EndpointArtifactPageId); - }); - } - - for (const { url, title } of grantedAccessPages) { - it(`should have access to: ${title}`, () => { - cy.visit(url); - getNoPrivilegesPage().should('not.exist'); - }); - } - - it(`should NOT have access to Host Isolation Exceptions`, () => { - ensureArtifactPageAuthzAccess( - 'none', - pageById.hostIsolationExceptions.id as EndpointArtifactPageId - ); - }); - - it('should have access to Fleet', () => { - visitFleetAgentList(); - getFleetAgentListTable().should('exist'); - }); + getFleetAgentListTable().should('exist'); }); }); - } -); + }); +}); From a32ca3b0a65f88fdabc78bb9add63727e910d515 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 9 Apr 2024 09:56:31 -0400 Subject: [PATCH 09/29] skip failing test suite (#171644) --- .../e2e/artifacts/artifact_tabs_in_policy_details.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifact_tabs_in_policy_details.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifact_tabs_in_policy_details.cy.ts index b6040691c485f..7fd516d217b95 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifact_tabs_in_policy_details.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifact_tabs_in_policy_details.cy.ts @@ -59,7 +59,8 @@ const visitArtifactTab = (tabId: string) => { cy.get(`#${tabId}`).click(); }; -describe('Artifact tabs in Policy Details page', { tags: ['@ess', '@serverless'] }, () => { +// Failing: See https://github.com/elastic/kibana/issues/171644 +describe.skip('Artifact tabs in Policy Details page', { tags: ['@ess', '@serverless'] }, () => { let endpointData: ReturnTypeFromChainable | undefined; before(() => { From 6b97bb5181ae8d8d1635c48c365c06d5ecdc5540 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Tue, 9 Apr 2024 09:03:22 -0500 Subject: [PATCH 10/29] fix lint error --- .../essentials_with_endpoint.roles.cy.ts | 364 +++++++++--------- 1 file changed, 184 insertions(+), 180 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts index 41b2f00dd9b41..cdef86bb1d4a7 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/roles/essentials_with_endpoint.roles.cy.ts @@ -24,223 +24,182 @@ import { } from '../../../screens'; // Failing: See https://github.com/elastic/kibana/issues/170985 -describe.skip('Roles for Security Essential PLI with Endpoint Essentials addon', { - tags: ['@serverless'], - env: { - ftrConfig: { - productTypes: [ - { product_line: 'security', product_tier: 'essentials' }, - { product_line: 'endpoint', product_tier: 'essentials' }, - ], +describe.skip( + 'Roles for Security Essential PLI with Endpoint Essentials addon', + { + tags: ['@serverless'], + env: { + ftrConfig: { + productTypes: [ + { product_line: 'security', product_tier: 'essentials' }, + { product_line: 'endpoint', product_tier: 'essentials' }, + ], + }, }, }, -}, () => { - const allPages = getEndpointManagementPageList(); - const pageById = getEndpointManagementPageMap(); + () => { + const allPages = getEndpointManagementPageList(); + const pageById = getEndpointManagementPageMap(); - let loadedEndpoints: CyIndexEndpointHosts; + let loadedEndpoints: CyIndexEndpointHosts; - before(() => { - indexEndpointHosts().then((response) => { - loadedEndpoints = response; + before(() => { + indexEndpointHosts().then((response) => { + loadedEndpoints = response; + }); + }); + + after(() => { + if (loadedEndpoints) { + loadedEndpoints.cleanup(); + } }); - }); - after(() => { - if (loadedEndpoints) { - loadedEndpoints.cleanup(); - } - }); + // roles `t1_analyst` and `t2_analyst` are the same as far as endpoint access + [ROLE.t1_analyst, ROLE.t2_analyst].forEach((roleName) => { + describe(`for role: ${roleName}`, () => { + const deniedPages = allPages.filter((page) => page.id !== 'endpointList'); + + beforeEach(() => { + login(roleName); + }); + + it('should have READ access to Endpoint list page', () => { + ensureEndpointListPageAuthzAccess('read', true); + }); - // roles `t1_analyst` and `t2_analyst` are the same as far as endpoint access - [ROLE.t1_analyst, ROLE.t2_analyst].forEach((roleName) => { - describe(`for role: ${roleName}`, () => { - const deniedPages = allPages.filter((page) => page.id !== 'endpointList'); + for (const { url, title } of deniedPages) { + it(`should NOT have access to: ${title}`, () => { + cy.visit(url); + getNoPrivilegesPage().should('exist'); + }); + } + + it('should NOT have access to Fleet', () => { + visitFleetAgentList(); + ensureFleetPermissionDeniedScreen(); + }); + }); + }); + + describe('for role: t3_analyst', () => { + const artifactPagesFullAccess = [ + pageById.trustedApps, + pageById.eventFilters, + pageById.blocklist, + ]; beforeEach(() => { - login(roleName); + login(ROLE.t3_analyst); }); - it('should have READ access to Endpoint list page', () => { - ensureEndpointListPageAuthzAccess('read', true); + it('should have access to Endpoint list page', () => { + ensureEndpointListPageAuthzAccess('all', true); }); - for (const { url, title } of deniedPages) { - it(`should NOT have access to: ${title}`, () => { - cy.visit(url); - getNoPrivilegesPage().should('exist'); + it('should have read access to Endpoint Policy Management', () => { + ensurePolicyListPageAuthzAccess('read', true); + ensurePolicyDetailsPageAuthzAccess( + loadedEndpoints.data.integrationPolicies[0].id, + 'read', + true + ); + }); + + for (const { title, id } of artifactPagesFullAccess) { + it(`should have CRUD access to: ${title}`, () => { + ensureArtifactPageAuthzAccess('all', id as EndpointArtifactPageId); }); } + it(`should NOT have access to Host Isolation Exceptions`, () => { + ensureArtifactPageAuthzAccess( + 'none', + pageById.hostIsolationExceptions.id as EndpointArtifactPageId + ); + }); + it('should NOT have access to Fleet', () => { visitFleetAgentList(); ensureFleetPermissionDeniedScreen(); }); }); - }); - - describe('for role: t3_analyst', () => { - const artifactPagesFullAccess = [ - pageById.trustedApps, - pageById.eventFilters, - pageById.blocklist, - ]; - - beforeEach(() => { - login(ROLE.t3_analyst); - }); - - it('should have access to Endpoint list page', () => { - ensureEndpointListPageAuthzAccess('all', true); - }); - it('should have read access to Endpoint Policy Management', () => { - ensurePolicyListPageAuthzAccess('read', true); - ensurePolicyDetailsPageAuthzAccess( - loadedEndpoints.data.integrationPolicies[0].id, - 'read', - true - ); - }); + describe('for role: threat_intelligence_analyst', () => { + const deniedPages = allPages.filter(({ id }) => id !== 'blocklist' && id !== 'endpointList'); - for (const { title, id } of artifactPagesFullAccess) { - it(`should have CRUD access to: ${title}`, () => { - ensureArtifactPageAuthzAccess('all', id as EndpointArtifactPageId); + beforeEach(() => { + login(ROLE.threat_intelligence_analyst); }); - } - - it(`should NOT have access to Host Isolation Exceptions`, () => { - ensureArtifactPageAuthzAccess( - 'none', - pageById.hostIsolationExceptions.id as EndpointArtifactPageId - ); - }); - - it('should NOT have access to Fleet', () => { - visitFleetAgentList(); - ensureFleetPermissionDeniedScreen(); - }); - }); - - describe('for role: threat_intelligence_analyst', () => { - const deniedPages = allPages.filter(({ id }) => id !== 'blocklist' && id !== 'endpointList'); - beforeEach(() => { - login(ROLE.threat_intelligence_analyst); - }); + it('should have access to Endpoint list page', () => { + ensureEndpointListPageAuthzAccess('read', true); + }); - it('should have access to Endpoint list page', () => { - ensureEndpointListPageAuthzAccess('read', true); - }); + it(`should have ALL access to: Blocklist`, () => { + cy.visit(pageById.blocklist.url); + getArtifactListEmptyStateAddButton(pageById.blocklist.id as EndpointArtifactPageId).should( + 'exist' + ); + }); - it(`should have ALL access to: Blocklist`, () => { - cy.visit(pageById.blocklist.url); - getArtifactListEmptyStateAddButton(pageById.blocklist.id as EndpointArtifactPageId).should( - 'exist' - ); - }); + for (const { url, title } of deniedPages) { + it(`should NOT have access to: ${title}`, () => { + cy.visit(url); + getNoPrivilegesPage().should('exist'); + }); + } - for (const { url, title } of deniedPages) { - it(`should NOT have access to: ${title}`, () => { - cy.visit(url); - getNoPrivilegesPage().should('exist'); + it('should NOT have access to Fleet', () => { + visitFleetAgentList(); + ensureFleetPermissionDeniedScreen(); }); - } - - it('should NOT have access to Fleet', () => { - visitFleetAgentList(); - ensureFleetPermissionDeniedScreen(); }); - }); - describe('for role: rule_author', () => { - const artifactPagesFullAccess = [ - pageById.trustedApps, - pageById.eventFilters, - pageById.blocklist, - ]; - - beforeEach(() => { - login(ROLE.rule_author); - }); + describe('for role: rule_author', () => { + const artifactPagesFullAccess = [ + pageById.trustedApps, + pageById.eventFilters, + pageById.blocklist, + ]; - for (const { id, title } of artifactPagesFullAccess) { - it(`should have CRUD access to: ${title}`, () => { - ensureArtifactPageAuthzAccess('all', id as EndpointArtifactPageId); + beforeEach(() => { + login(ROLE.rule_author); }); - } - - it('should have access to Endpoint list page', () => { - ensureEndpointListPageAuthzAccess('all', true); - }); - it('should have access to policy management', () => { - ensurePolicyListPageAuthzAccess('all', true); - ensurePolicyDetailsPageAuthzAccess( - loadedEndpoints.data.integrationPolicies[0].id, - 'all', - true - ); - }); - - it(`should NOT have access to Host Isolation Exceptions`, () => { - ensureArtifactPageAuthzAccess( - 'none', - pageById.hostIsolationExceptions.id as EndpointArtifactPageId - ); - }); + for (const { id, title } of artifactPagesFullAccess) { + it(`should have CRUD access to: ${title}`, () => { + ensureArtifactPageAuthzAccess('all', id as EndpointArtifactPageId); + }); + } - it('should NOT have access to Fleet', () => { - visitFleetAgentList(); - ensureFleetPermissionDeniedScreen(); - }); - }); - - describe('for role: soc_manager', () => { - const artifactPagesFullAccess = [ - pageById.trustedApps, - pageById.eventFilters, - pageById.blocklist, - ]; - const grantedAccessPages = [pageById.endpointList, pageById.policyList]; - - beforeEach(() => { - login(ROLE.soc_manager); - }); + it('should have access to Endpoint list page', () => { + ensureEndpointListPageAuthzAccess('all', true); + }); - for (const { id, title } of artifactPagesFullAccess) { - it(`should have CRUD access to: ${title}`, () => { - ensureArtifactPageAuthzAccess('all', id as EndpointArtifactPageId); + it('should have access to policy management', () => { + ensurePolicyListPageAuthzAccess('all', true); + ensurePolicyDetailsPageAuthzAccess( + loadedEndpoints.data.integrationPolicies[0].id, + 'all', + true + ); }); - } - for (const { url, title } of grantedAccessPages) { - it(`should have access to: ${title}`, () => { - cy.visit(url); - getNoPrivilegesPage().should('not.exist'); + it(`should NOT have access to Host Isolation Exceptions`, () => { + ensureArtifactPageAuthzAccess( + 'none', + pageById.hostIsolationExceptions.id as EndpointArtifactPageId + ); }); - } - it(`should NOT have access to Host Isolation Exceptions`, () => { - ensureArtifactPageAuthzAccess( - 'none', - pageById.hostIsolationExceptions.id as EndpointArtifactPageId - ); + it('should NOT have access to Fleet', () => { + visitFleetAgentList(); + ensureFleetPermissionDeniedScreen(); + }); }); - it('should NOT have access to Fleet', () => { - visitFleetAgentList(); - ensureFleetPermissionDeniedScreen(); - }); - }); - - // Endpoint Operations Manager, Endpoint Policy Manager and Platform Engineer currently have the same level of access - [ - ROLE.platform_engineer, - ROLE.endpoint_operations_analyst, - ROLE.endpoint_policy_manager, - ].forEach((roleName) => { - describe(`for role: ${roleName}`, () => { + describe('for role: soc_manager', () => { const artifactPagesFullAccess = [ pageById.trustedApps, pageById.eventFilters, @@ -249,7 +208,7 @@ describe.skip('Roles for Security Essential PLI with Endpoint Essentials addon', const grantedAccessPages = [pageById.endpointList, pageById.policyList]; beforeEach(() => { - login(roleName); + login(ROLE.soc_manager); }); for (const { id, title } of artifactPagesFullAccess) { @@ -272,10 +231,55 @@ describe.skip('Roles for Security Essential PLI with Endpoint Essentials addon', ); }); - it('should have access to Fleet', () => { + it('should NOT have access to Fleet', () => { visitFleetAgentList(); - getFleetAgentListTable().should('exist'); + ensureFleetPermissionDeniedScreen(); + }); + }); + + // Endpoint Operations Manager, Endpoint Policy Manager and Platform Engineer currently have the same level of access + [ + ROLE.platform_engineer, + ROLE.endpoint_operations_analyst, + ROLE.endpoint_policy_manager, + ].forEach((roleName) => { + describe(`for role: ${roleName}`, () => { + const artifactPagesFullAccess = [ + pageById.trustedApps, + pageById.eventFilters, + pageById.blocklist, + ]; + const grantedAccessPages = [pageById.endpointList, pageById.policyList]; + + beforeEach(() => { + login(roleName); + }); + + for (const { id, title } of artifactPagesFullAccess) { + it(`should have CRUD access to: ${title}`, () => { + ensureArtifactPageAuthzAccess('all', id as EndpointArtifactPageId); + }); + } + + for (const { url, title } of grantedAccessPages) { + it(`should have access to: ${title}`, () => { + cy.visit(url); + getNoPrivilegesPage().should('not.exist'); + }); + } + + it(`should NOT have access to Host Isolation Exceptions`, () => { + ensureArtifactPageAuthzAccess( + 'none', + pageById.hostIsolationExceptions.id as EndpointArtifactPageId + ); + }); + + it('should have access to Fleet', () => { + visitFleetAgentList(); + getFleetAgentListTable().should('exist'); + }); }); }); - }); -}); + } +); From cbf73ec1970e83792f55882738c6f0cb42f2d5d3 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Tue, 9 Apr 2024 09:04:11 -0500 Subject: [PATCH 11/29] fix lint error --- ...dpoint_list_with_security_essentials.cy.ts | 62 ++++++++++--------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts index e8ea8d5ae1d70..7f003848db88c 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts @@ -16,41 +16,45 @@ import { } from '../../screens'; // Failing: See https://github.com/elastic/kibana/issues/171643 -describe.skip('When on the Endpoint List in Security Essentials PLI', { - tags: ['@serverless'], - env: { - ftrConfig: { - productTypes: [{ product_line: 'security', product_tier: 'essentials' }], +describe.skip( + 'When on the Endpoint List in Security Essentials PLI', + { + tags: ['@serverless'], + env: { + ftrConfig: { + productTypes: [{ product_line: 'security', product_tier: 'essentials' }], + }, }, }, -}, () => { - describe('and Isolated hosts exist', () => { - let indexedEndpointData: CyIndexEndpointHosts; + () => { + describe('and Isolated hosts exist', () => { + let indexedEndpointData: CyIndexEndpointHosts; - before(() => { - indexEndpointHosts({ isolation: true }).then((response) => { - indexedEndpointData = response; + before(() => { + indexEndpointHosts({ isolation: true }).then((response) => { + indexedEndpointData = response; + }); }); - }); - after(() => { - if (indexedEndpointData) { - indexedEndpointData.cleanup(); - } - }); + after(() => { + if (indexedEndpointData) { + indexedEndpointData.cleanup(); + } + }); - beforeEach(() => { - login(); - visitEndpointList(); - openRowActionMenu(); - }); + beforeEach(() => { + login(); + visitEndpointList(); + openRowActionMenu(); + }); - it('should display `release` options in host row actions', () => { - getUnIsolateActionMenuItem().should('exist'); - }); + it('should display `release` options in host row actions', () => { + getUnIsolateActionMenuItem().should('exist'); + }); - it('should NOT display access to response console', () => { - getConsoleActionMenuItem().should('not.exist'); + it('should NOT display access to response console', () => { + getConsoleActionMenuItem().should('not.exist'); + }); }); - }); -}); + } +); From 923d683dc9757786728962ef85d68a152268561c Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 9 Apr 2024 10:06:20 -0400 Subject: [PATCH 12/29] skip failing test suite (#172549) --- .../e2e/response_actions/response_actions_history.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_actions_history.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_actions_history.cy.ts index a36f7e3beaec4..fb953d22f23be 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_actions_history.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_actions_history.cy.ts @@ -10,7 +10,8 @@ import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts'; import { login } from '../../tasks/login'; import { loadPage } from '../../tasks/common'; -describe('Response actions history page', { tags: ['@ess', '@serverless'] }, () => { +// Failing: See https://github.com/elastic/kibana/issues/172549 +describe.skip('Response actions history page', { tags: ['@ess', '@serverless'] }, () => { let endpointData: ReturnTypeFromChainable; before(() => { From 66fcd179bfbf9b431446f19ad677933e20ae1db0 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 9 Apr 2024 10:07:35 -0400 Subject: [PATCH 13/29] skip failing test suite (#169894) --- .../management/cypress/e2e/response_actions/responder.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/responder.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/responder.cy.ts index e737779ad8ff9..4968fb9bda21a 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/responder.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/responder.cy.ts @@ -21,7 +21,8 @@ import { indexNewCase } from '../../tasks/index_new_case'; import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts'; import { indexEndpointRuleAlerts } from '../../tasks/index_endpoint_rule_alerts'; -describe('When accessing Endpoint Response Console', { tags: ['@ess', '@serverless'] }, () => { +// Failing: See https://github.com/elastic/kibana/issues/169894 +describe.skip('When accessing Endpoint Response Console', { tags: ['@ess', '@serverless'] }, () => { const performResponderSanityChecks = () => { openResponderActionLogFlyout(); // Ensure the popover in the action log date quick select picker is accessible From 5336a237db4b75aa8c20cb636756d540f454ff13 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 9 Apr 2024 16:22:10 +0200 Subject: [PATCH 14/29] [HTTP/OAS] Prepare `@kbn/config-schema` for generating OAS (#180184) ## Summary Introduces a set of meta fields that will be used to track metadata lost in how we currently use `joi` inside of `@kbn/config-schema`. ## Notes * Related https://github.com/elastic/kibana/issues/180056 * Changes cherry-picked from https://github.com/elastic/kibana/pull/156357 * Changes are not used for anything in this PR, they are intended to enable our OAS generation scripts --- packages/kbn-config-schema/index.ts | 14 + .../kbn-config-schema/src/oas_meta_fields.ts | 17 + .../{map_of_type.test.ts => map_type.test.ts} | 12 + .../kbn-config-schema/src/types/map_type.ts | 8 +- .../src/types/maybe_type.test.ts | 7 + .../kbn-config-schema/src/types/maybe_type.ts | 2 + .../src/types/record_type.test.ts | 12 + .../src/types/record_type.ts | 8 +- .../src/types/string_type.test.ts | 12 + .../src/types/string_type.ts | 35 +- .../kbn-config-schema/src/types/type.test.ts | 23 + packages/kbn-config-schema/src/types/type.ts | 6 + .../connector_types.test.ts.snap | 524 +++++++++++++ ...s_upgrade_and_rollback_checks.test.ts.snap | 737 ++++++++++++++++++ 14 files changed, 1401 insertions(+), 16 deletions(-) create mode 100644 packages/kbn-config-schema/src/oas_meta_fields.ts rename packages/kbn-config-schema/src/types/{map_of_type.test.ts => map_type.test.ts} (94%) create mode 100644 packages/kbn-config-schema/src/types/type.test.ts diff --git a/packages/kbn-config-schema/index.ts b/packages/kbn-config-schema/index.ts index 57c61c125ec73..0aec0ae1f5a1e 100644 --- a/packages/kbn-config-schema/index.ts +++ b/packages/kbn-config-schema/index.ts @@ -238,3 +238,17 @@ export const schema = { }; export type Schema = typeof schema; + +import { + META_FIELD_X_OAS_OPTIONAL, + META_FIELD_X_OAS_MAX_LENGTH, + META_FIELD_X_OAS_MIN_LENGTH, + META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES, +} from './src/oas_meta_fields'; + +export const metaFields = Object.freeze({ + META_FIELD_X_OAS_OPTIONAL, + META_FIELD_X_OAS_MAX_LENGTH, + META_FIELD_X_OAS_MIN_LENGTH, + META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES, +}); diff --git a/packages/kbn-config-schema/src/oas_meta_fields.ts b/packages/kbn-config-schema/src/oas_meta_fields.ts new file mode 100644 index 0000000000000..e54751f36f099 --- /dev/null +++ b/packages/kbn-config-schema/src/oas_meta_fields.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +/** + * These fields are used in Joi meta to capture additional information used + * by OpenAPI spec generator. + */ +export const META_FIELD_X_OAS_OPTIONAL = 'x-oas-optional' as const; +export const META_FIELD_X_OAS_MIN_LENGTH = 'x-oas-min-length' as const; +export const META_FIELD_X_OAS_MAX_LENGTH = 'x-oas-max-length' as const; +export const META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES = + 'x-oas-get-additional-properties' as const; diff --git a/packages/kbn-config-schema/src/types/map_of_type.test.ts b/packages/kbn-config-schema/src/types/map_type.test.ts similarity index 94% rename from packages/kbn-config-schema/src/types/map_of_type.test.ts rename to packages/kbn-config-schema/src/types/map_type.test.ts index 7552a6d65a621..f1cb809a16243 100644 --- a/packages/kbn-config-schema/src/types/map_of_type.test.ts +++ b/packages/kbn-config-schema/src/types/map_type.test.ts @@ -7,6 +7,7 @@ */ import { schema } from '../..'; +import { META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES } from '../oas_meta_fields'; test('handles object as input', () => { const type = schema.mapOf(schema.string(), schema.string()); @@ -186,6 +187,17 @@ test('error preserves full path', () => { ); }); +test('meta', () => { + const stringSchema = schema.string(); + const type = schema.mapOf(schema.string(), stringSchema); + const result = type + .getSchema() + .describe() + .metas![0][META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES](); + + expect(result).toBe(stringSchema.getSchema()); +}); + describe('#extendsDeep', () => { describe('#keyType', () => { const type = schema.mapOf(schema.string(), schema.object({ foo: schema.string() })); diff --git a/packages/kbn-config-schema/src/types/map_type.ts b/packages/kbn-config-schema/src/types/map_type.ts index 61caf76efc613..cf14d7af7f1cb 100644 --- a/packages/kbn-config-schema/src/types/map_type.ts +++ b/packages/kbn-config-schema/src/types/map_type.ts @@ -9,6 +9,7 @@ import typeDetect from 'type-detect'; import { SchemaTypeError, SchemaTypesError } from '../errors'; import { internals } from '../internals'; +import { META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES } from '../oas_meta_fields'; import { Type, TypeOptions, ExtendsDeepOptions } from './type'; export type MapOfOptions = TypeOptions>; @@ -20,7 +21,12 @@ export class MapOfType extends Type> { constructor(keyType: Type, valueType: Type, options: MapOfOptions = {}) { const defaultValue = options.defaultValue; - const schema = internals.map().entries(keyType.getSchema(), valueType.getSchema()); + const schema = internals + .map() + .entries(keyType.getSchema(), valueType.getSchema()) + .meta({ + [META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES]: () => valueType.getSchema(), + }); super(schema, { ...options, diff --git a/packages/kbn-config-schema/src/types/maybe_type.test.ts b/packages/kbn-config-schema/src/types/maybe_type.test.ts index ff69c2bb36045..312b88520a12a 100644 --- a/packages/kbn-config-schema/src/types/maybe_type.test.ts +++ b/packages/kbn-config-schema/src/types/maybe_type.test.ts @@ -7,6 +7,7 @@ */ import { schema } from '../..'; +import { META_FIELD_X_OAS_OPTIONAL } from '../oas_meta_fields'; test('returns value if specified', () => { const type = schema.maybe(schema.string()); @@ -96,6 +97,12 @@ describe('maybe + object', () => { }); }); +test('meta', () => { + const maybeString = schema.maybe(schema.string()); + const result = maybeString.getSchema().describe().metas[0]; + expect(result).toEqual({ [META_FIELD_X_OAS_OPTIONAL]: true }); +}); + describe('#extendsDeep', () => { const type = schema.maybe(schema.object({ foo: schema.string() })); diff --git a/packages/kbn-config-schema/src/types/maybe_type.ts b/packages/kbn-config-schema/src/types/maybe_type.ts index e90434077cc36..6cd88dfc9a7cd 100644 --- a/packages/kbn-config-schema/src/types/maybe_type.ts +++ b/packages/kbn-config-schema/src/types/maybe_type.ts @@ -8,6 +8,7 @@ import { Type, ExtendsDeepOptions } from './type'; +import { META_FIELD_X_OAS_OPTIONAL } from '../oas_meta_fields'; export class MaybeType extends Type { private readonly maybeType: Type; @@ -16,6 +17,7 @@ export class MaybeType extends Type { type .getSchema() .optional() + .meta({ [META_FIELD_X_OAS_OPTIONAL]: true }) .default(() => undefined) ); this.maybeType = type; diff --git a/packages/kbn-config-schema/src/types/record_type.test.ts b/packages/kbn-config-schema/src/types/record_type.test.ts index 9bfd4fab31b7a..609c17eb43d8e 100644 --- a/packages/kbn-config-schema/src/types/record_type.test.ts +++ b/packages/kbn-config-schema/src/types/record_type.test.ts @@ -7,6 +7,7 @@ */ import { schema } from '../..'; +import { META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES } from '../oas_meta_fields'; test('handles object as input', () => { const type = schema.recordOf(schema.string(), schema.string()); @@ -208,3 +209,14 @@ describe('#extendsDeep', () => { ).toThrowErrorMatchingInlineSnapshot(`"[key.bar]: definition for this key is missing"`); }); }); + +test('meta', () => { + const stringSchema = schema.string(); + const type = schema.mapOf(schema.string(), stringSchema); + const result = type + .getSchema() + .describe() + .metas![0][META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES](); + + expect(result).toBe(stringSchema.getSchema()); +}); diff --git a/packages/kbn-config-schema/src/types/record_type.ts b/packages/kbn-config-schema/src/types/record_type.ts index 782263d9932ea..ac083ada116bc 100644 --- a/packages/kbn-config-schema/src/types/record_type.ts +++ b/packages/kbn-config-schema/src/types/record_type.ts @@ -10,6 +10,7 @@ import typeDetect from 'type-detect'; import { SchemaTypeError, SchemaTypesError } from '../errors'; import { internals } from '../internals'; import { Type, TypeOptions, ExtendsDeepOptions } from './type'; +import { META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES } from '../oas_meta_fields'; export type RecordOfOptions = TypeOptions>; @@ -19,7 +20,12 @@ export class RecordOfType extends Type> { private readonly options: RecordOfOptions; constructor(keyType: Type, valueType: Type, options: RecordOfOptions = {}) { - const schema = internals.record().entries(keyType.getSchema(), valueType.getSchema()); + const schema = internals + .record() + .entries(keyType.getSchema(), valueType.getSchema()) + .meta({ + [META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES]: () => valueType.getSchema(), + }); super(schema, options); this.keyType = keyType; diff --git a/packages/kbn-config-schema/src/types/string_type.test.ts b/packages/kbn-config-schema/src/types/string_type.test.ts index d07b52983d88c..0f567cd2b7e20 100644 --- a/packages/kbn-config-schema/src/types/string_type.test.ts +++ b/packages/kbn-config-schema/src/types/string_type.test.ts @@ -7,6 +7,7 @@ */ import { schema } from '../..'; +import { META_FIELD_X_OAS_MAX_LENGTH, META_FIELD_X_OAS_MIN_LENGTH } from '../oas_meta_fields'; test('returns value is string and defined', () => { expect(schema.string().validate('test')).toBe('test'); @@ -166,6 +167,17 @@ describe('#defaultValue', () => { }); }); +test('meta', () => { + const string = schema.string({ minLength: 1, maxLength: 3 }); + const [meta1, meta2] = string.getSchema().describe().metas; + expect(meta1).toEqual({ + [META_FIELD_X_OAS_MIN_LENGTH]: 1, + }); + expect(meta2).toEqual({ + [META_FIELD_X_OAS_MAX_LENGTH]: 3, + }); +}); + describe('#validate', () => { test('is called with input value', () => { let calledWith; diff --git a/packages/kbn-config-schema/src/types/string_type.ts b/packages/kbn-config-schema/src/types/string_type.ts index e5251013e3a7e..999a4d85fb384 100644 --- a/packages/kbn-config-schema/src/types/string_type.ts +++ b/packages/kbn-config-schema/src/types/string_type.ts @@ -10,6 +10,8 @@ import typeDetect from 'type-detect'; import { internals } from '../internals'; import { Type, TypeOptions, convertValidationFunction } from './type'; +import { META_FIELD_X_OAS_MIN_LENGTH, META_FIELD_X_OAS_MAX_LENGTH } from '../oas_meta_fields'; + export type StringOptions = TypeOptions & { minLength?: number; maxLength?: number; @@ -37,24 +39,29 @@ export class StringType extends Type { } return value; }); + if (options.minLength !== undefined) { - schema = schema.custom( - convertValidationFunction((value) => { - if (value.length < options.minLength!) { - return `value has length [${value.length}] but it must have a minimum length of [${options.minLength}].`; - } - }) - ); + schema = schema + .custom( + convertValidationFunction((value) => { + if (value.length < options.minLength!) { + return `value has length [${value.length}] but it must have a minimum length of [${options.minLength}].`; + } + }) + ) + .meta({ [META_FIELD_X_OAS_MIN_LENGTH]: options.minLength }); } if (options.maxLength !== undefined) { - schema = schema.custom( - convertValidationFunction((value) => { - if (value.length > options.maxLength!) { - return `value has length [${value.length}] but it must have a maximum length of [${options.maxLength}].`; - } - }) - ); + schema = schema + .custom( + convertValidationFunction((value) => { + if (value.length > options.maxLength!) { + return `value has length [${value.length}] but it must have a maximum length of [${options.maxLength}].`; + } + }) + ) + .meta({ [META_FIELD_X_OAS_MAX_LENGTH]: options.maxLength }); } schema.type = 'string'; diff --git a/packages/kbn-config-schema/src/types/type.test.ts b/packages/kbn-config-schema/src/types/type.test.ts new file mode 100644 index 0000000000000..9cb61b88aa030 --- /dev/null +++ b/packages/kbn-config-schema/src/types/type.test.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 { get } from 'lodash'; +import { internals } from '../internals'; +import { Type, TypeOptions } from './type'; + +class MyType extends Type { + constructor(opts: TypeOptions = {}) { + super(internals.any(), opts); + } +} + +test('describe', () => { + const type = new MyType({ description: 'my description' }); + const meta = type.getSchema().describe(); + expect(get(meta, 'flags.description')).toBe('my description'); +}); diff --git a/packages/kbn-config-schema/src/types/type.ts b/packages/kbn-config-schema/src/types/type.ts index 8023da2dda920..145650d0e3d82 100644 --- a/packages/kbn-config-schema/src/types/type.ts +++ b/packages/kbn-config-schema/src/types/type.ts @@ -13,6 +13,8 @@ import { Reference } from '../references'; export interface TypeOptions { defaultValue?: T | Reference | (() => T); validate?: (value: T) => string | void; + /** A human-friendly description of this type to be used in documentation */ + description?: string; } export interface SchemaStructureEntry { @@ -86,6 +88,10 @@ export abstract class Type { schema = schema.custom(convertValidationFunction(options.validate)); } + if (options.description) { + schema = schema.description(options.description); + } + // Attach generic error handler only if it hasn't been attached yet since // only the last error handler is counted. if (schema.$_getFlag('error') === undefined) { diff --git a/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap b/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap index f27cc6ab83623..f85e0abce89c7 100644 --- a/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap +++ b/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap @@ -30,6 +30,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -114,6 +119,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -203,6 +213,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -219,6 +234,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "any", }, "stopSequences": Object { @@ -244,6 +264,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "system": Object { @@ -252,6 +277,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -268,6 +298,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "number", }, }, @@ -349,6 +384,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -365,6 +405,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "any", }, "stopSequences": Object { @@ -390,6 +435,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "system": Object { @@ -398,6 +448,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -414,6 +469,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "number", }, }, @@ -855,6 +915,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + ], "rules": Array [ Object { "args": Object { @@ -1520,6 +1585,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1536,6 +1606,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1552,6 +1627,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1588,6 +1668,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1604,6 +1689,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1620,6 +1710,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -2504,6 +2599,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + ], "rules": Array [ Object { "args": Object { @@ -3136,6 +3236,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + ], "rules": Array [ Object { "args": Object { @@ -3560,6 +3665,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 50, + }, + ], "rules": Array [ Object { "args": Object { @@ -3577,6 +3687,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3593,6 +3708,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3609,6 +3729,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 15000, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3631,6 +3759,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3674,6 +3810,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 512, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3694,6 +3838,14 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + Object { + "x-oas-max-length": 130, + }, + ], "rules": Array [ Object { "args": Object { @@ -3728,6 +3880,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 25000, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3812,6 +3972,11 @@ Object { }, }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "alternatives", }, "responders": Object { @@ -4052,6 +4217,11 @@ Object { "type": "alternatives", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4068,6 +4238,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 100, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4096,6 +4274,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 50, + }, + ], "rules": Array [ Object { "args": Object { @@ -4113,6 +4296,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4129,6 +4317,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 100, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4334,6 +4530,11 @@ Object { "type": "alternatives", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4384,6 +4585,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 25000, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4406,6 +4615,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 100, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4428,6 +4645,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 100, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4681,6 +4906,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4697,6 +4927,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4713,6 +4948,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4748,6 +4991,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 255, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4808,6 +5059,11 @@ Object { }, }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "alternatives", }, "group": Object { @@ -4816,6 +5072,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4879,6 +5140,11 @@ Object { "type": "object", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "severity": Object { @@ -4937,6 +5203,11 @@ Object { }, }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "alternatives", }, "source": Object { @@ -4945,6 +5216,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4961,6 +5237,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 1024, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4983,6 +5267,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -6543,6 +6832,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "appsVulnerabilityStatuses": Object { @@ -12250,6 +12544,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "appsVulnerabilityStatuses": Object { @@ -17957,6 +18256,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "appsVulnerabilityStatuses": Object { @@ -23664,6 +23968,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "appsVulnerabilityStatuses": Object { @@ -28663,6 +28972,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "computerName": Object { @@ -28671,6 +28985,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -28696,6 +29015,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -28712,6 +29036,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -28728,6 +29057,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -28744,6 +29078,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -28767,6 +29106,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -28783,6 +29127,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -28794,6 +29143,11 @@ Object { "type": "string", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -28807,6 +29161,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "scriptId": Object { @@ -28829,6 +29188,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -28845,6 +29209,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "number", }, "singularityxdrKeyword": Object { @@ -28853,6 +29222,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -28869,6 +29243,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -28885,6 +29264,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -32824,6 +33208,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -32880,6 +33269,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -32900,6 +33294,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -32925,6 +33324,11 @@ Object { "type": "object", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -32959,6 +33363,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -33026,6 +33435,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -33105,6 +33519,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -33138,6 +33557,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -33152,6 +33576,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -33237,6 +33666,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -33270,6 +33704,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -34626,6 +35065,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -34764,6 +35208,11 @@ Object { "type": "number", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -34777,6 +35226,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -34883,6 +35337,11 @@ Object { "type": "number", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -34896,6 +35355,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -35205,6 +35669,11 @@ Object { }, }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "alternatives", }, "ca": Object { @@ -35213,6 +35682,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -35255,6 +35729,11 @@ Object { }, }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "alternatives", }, "hasAuth": Object { @@ -35277,6 +35756,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + ], "rules": Array [ Object { "args": Object { @@ -35422,6 +35906,11 @@ Object { }, }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "alternatives", }, }, @@ -35668,6 +36157,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -35904,6 +36398,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -35920,6 +36419,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -35936,6 +36440,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -35966,6 +36475,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -35982,6 +36496,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -35998,6 +36517,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { diff --git a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap index 0313aafa1be5e..bbfa2fb3bb28b 100644 --- a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap +++ b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap @@ -16,6 +16,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -87,6 +95,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -148,6 +161,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -244,6 +262,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -442,6 +465,11 @@ Object { "type": "object", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -464,6 +492,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -521,6 +554,11 @@ Object { }, }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "alternatives", }, "termSize": Object { @@ -529,6 +567,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -679,6 +722,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -704,6 +755,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -789,6 +845,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -809,6 +870,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -831,12 +897,22 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "any", }, "boundaryIndexTitle": Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -859,6 +935,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -879,6 +963,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -899,6 +988,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -919,6 +1013,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -939,6 +1038,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -959,6 +1063,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -979,6 +1088,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -1001,6 +1115,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "any", }, }, @@ -1029,6 +1148,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1073,6 +1200,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1121,6 +1253,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -1149,6 +1286,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -1186,6 +1328,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1208,6 +1358,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1339,6 +1494,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], "rules": Array [ Object { "args": Object { @@ -1554,6 +1714,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1570,6 +1735,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1640,6 +1810,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1673,6 +1848,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "searchConfiguration": Object { @@ -1731,6 +1911,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + ], "rules": Array [ Object { "args": Object { @@ -1773,6 +1958,11 @@ Object { "type": "object", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -1786,6 +1976,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -1808,6 +2003,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "windowSize": Object { @@ -1931,6 +2131,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "searchConfiguration": Object { @@ -1989,6 +2194,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + ], "rules": Array [ Object { "args": Object { @@ -2031,6 +2241,11 @@ Object { "type": "object", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -2044,6 +2259,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -2066,6 +2286,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -2082,6 +2307,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -2098,6 +2328,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "windowSize": Object { @@ -2177,6 +2412,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "searchConfiguration": Object { @@ -2235,6 +2475,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + ], "rules": Array [ Object { "args": Object { @@ -2277,6 +2522,11 @@ Object { "type": "object", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -2290,6 +2540,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -2312,6 +2567,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -2328,6 +2588,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -2344,6 +2609,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "windowSize": Object { @@ -2393,6 +2663,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "criteria": Object { @@ -2490,6 +2765,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -2511,6 +2791,11 @@ Object { "type": "any", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -2579,6 +2864,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -2610,6 +2900,11 @@ Object { "type": "number", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, }, @@ -2629,6 +2924,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -2700,6 +3000,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "alertOnNoData": Object { @@ -2708,6 +3013,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "criteria": Object { @@ -2734,6 +3044,11 @@ Object { "only": true, "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "any", }, "comparator": Object { @@ -2762,6 +3077,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -2778,6 +3098,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -2913,6 +3238,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3053,6 +3383,11 @@ Object { }, }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "alternatives", }, "searchConfiguration": Object { @@ -3084,6 +3419,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + ], "rules": Array [ Object { "args": Object { @@ -3119,6 +3459,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3157,6 +3505,11 @@ Object { "type": "object", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "index": Object { @@ -3196,6 +3549,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "allowNoIndex": Object { @@ -3204,6 +3562,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "fieldAttrs": Object { @@ -3212,6 +3575,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3244,6 +3615,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "number", }, "customDescription": Object { @@ -3252,6 +3628,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 300, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3274,6 +3658,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3304,6 +3693,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3336,6 +3733,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3352,6 +3754,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "any", }, }, @@ -3374,6 +3781,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3406,6 +3821,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "count": Object { @@ -3414,6 +3834,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3430,6 +3855,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 300, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3452,6 +3885,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3485,6 +3923,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "format": Object { @@ -3500,6 +3943,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3516,9 +3964,19 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "any", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -3530,6 +3988,11 @@ Object { "flags": Object { "error": [Function], }, + "metas": Array [ + Object { + "x-oas-max-length": 1000, + }, + ], "rules": Array [ Object { "args": Object { @@ -3552,6 +4015,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "runtimeField": Object { @@ -3577,6 +4045,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 300, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3599,6 +4075,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3622,6 +4103,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3638,9 +4124,19 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "any", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -3654,6 +4150,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3686,6 +4187,11 @@ Object { "type": "string", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -3810,6 +4316,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3842,6 +4356,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 300, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3864,6 +4386,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3887,6 +4414,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -3903,9 +4435,19 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "any", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -3919,6 +4461,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4057,6 +4604,11 @@ Object { "type": "string", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -4084,6 +4636,11 @@ Object { }, }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "alternatives", }, "script": Object { @@ -4092,6 +4649,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 1000000, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4114,6 +4679,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "searchable": Object { @@ -4122,6 +4692,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "shortDotsEnable": Object { @@ -4130,6 +4705,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "boolean", }, "subType": Object { @@ -4161,6 +4741,11 @@ Object { "type": "string", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -4190,6 +4775,11 @@ Object { "type": "string", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -4198,6 +4788,11 @@ Object { "type": "object", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -4211,6 +4806,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 1000, + }, + ], "rules": Array [ Object { "args": Object { @@ -4247,6 +4847,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4263,6 +4868,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4296,6 +4906,11 @@ Object { "type": "string", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "runtimeFieldMap": Object { @@ -4304,6 +4919,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4342,6 +4965,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 300, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4364,6 +4995,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4387,6 +5023,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4403,9 +5044,19 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "any", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -4419,6 +5070,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4451,6 +5107,11 @@ Object { "type": "string", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -4575,6 +5236,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-get-additional-properties": [Function], + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4607,6 +5276,14 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-max-length": 300, + }, + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4629,6 +5306,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4652,6 +5334,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4668,9 +5355,19 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "any", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -4684,6 +5381,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4822,6 +5524,11 @@ Object { "type": "string", }, }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -4905,6 +5612,11 @@ Object { }, }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "alternatives", }, "value": Object { @@ -4930,6 +5642,11 @@ Object { "type": "object", }, ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "type": "array", }, "timeFieldName": Object { @@ -4938,6 +5655,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4968,6 +5690,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { @@ -4986,6 +5713,11 @@ Object { "unknown": true, }, "keys": Object {}, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "preferences": Object { "stripUnknown": Object { "objects": false, @@ -4999,6 +5731,11 @@ Object { "error": [Function], "presence": "optional", }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], "rules": Array [ Object { "args": Object { From 29e3ccd6262f4b05e469ac63e357639d66fd5483 Mon Sep 17 00:00:00 2001 From: Katerina Date: Tue, 9 Apr 2024 17:25:18 +0300 Subject: [PATCH 15/29] [APM] Add tooltip for service health status column (#180343) ## Summary fixes https://github.com/elastic/kibana/issues/179038 ## After ![image](https://github.com/elastic/kibana/assets/3369346/e51b3d15-1308-416f-abd3-b2cdea38a76d) --- .../service_inventory/service_list/index.tsx | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_inventory/service_list/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_inventory/service_list/index.tsx index 6c849e97fcd3d..e42fd862dc058 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_inventory/service_list/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_inventory/service_list/index.tsx @@ -10,6 +10,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiIcon, + EuiIconTip, EuiLink, EuiSpacer, EuiText, @@ -153,9 +154,27 @@ export function getServiceColumns({ ? [ { field: ServiceInventoryFieldName.HealthStatus, - name: i18n.translate('xpack.apm.servicesTable.healthColumnLabel', { - defaultMessage: 'Health', - }), + name: ( + <> + {i18n.translate('xpack.apm.servicesTable.healthColumnLabel', { + defaultMessage: 'Health', + })}{' '} + + + ), width: `${unit * 6}px`, sortable: true, render: (_, { healthStatus }) => { From 3e08d4d6db35bc959219d930709a12f3dbe4839e Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Tue, 9 Apr 2024 07:37:22 -0700 Subject: [PATCH 16/29] [DOCS] Add HTTP header example for webhook connectors (#180092) --- .../management/connectors/action-types/cases-webhook.asciidoc | 1 + docs/management/connectors/action-types/webhook.asciidoc | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/management/connectors/action-types/cases-webhook.asciidoc b/docs/management/connectors/action-types/cases-webhook.asciidoc index 8610c4593d513..3d5bfecffcb3b 100644 --- a/docs/management/connectors/action-types/cases-webhook.asciidoc +++ b/docs/management/connectors/action-types/cases-webhook.asciidoc @@ -53,6 +53,7 @@ image::management/connectors/images/cases-webhook-connector-comments.png[Add cas Add HTTP header:: A set of key-value pairs sent as headers with the request URLs for the create case, update case, get case, and create comment methods. +For example, set `Content-Type` to the appropriate media type for your requests. Create case method:: The REST API HTTP request method to create a case in the third-party system: `post`(default), `put`, or `patch`. diff --git a/docs/management/connectors/action-types/webhook.asciidoc b/docs/management/connectors/action-types/webhook.asciidoc index 1868f96d14c1d..d9a4dd43daeaf 100644 --- a/docs/management/connectors/action-types/webhook.asciidoc +++ b/docs/management/connectors/action-types/webhook.asciidoc @@ -34,7 +34,9 @@ Authentication:: The authentication type: none, basic, or SSL. If you choose basic authentication, you must provide a user name and password. If you choose SSL authentication, you must provide SSL server certificate authentication data in a CRT and key file format or a PFX file format. You can also optionally provide a passphrase if the files are password-protected. -HTTP headers:: A set of key-value pairs sent as headers with the request. +HTTP headers:: +A set of key-value pairs sent as headers with the request. +For example, set `Content-Type` to the appropriate media type for your requests. Certificate authority:: A certificate authority (CA) that the connector can trust, for example to sign and validate server certificates. This option is available for all authentication types. From d4282ee6301651ec4c29a7c2462231d7b7a08799 Mon Sep 17 00:00:00 2001 From: Gloria Hornero Date: Tue, 9 Apr 2024 17:02:34 +0200 Subject: [PATCH 17/29] [Security Solution] Allows to execute Cypress tests using projects with overridden images (#180285) ## Summary To make sure that our Cypress tests are working fine on MKI environments we are executing them in our periodic pipeline. When the pipeline is triggered, we built a new image of the latest commit available in main, we create a project in QA overriding the image and we execute our Cypress tests using that created project. Currently our `yarn cypress:open:qa:serverless` script, creates a project in QA using the last available version, so, if there is a test failing in the periodic pipeline, currently there is no easy way to execute it in our locals. To facilitate this work, this PR we are introducing the `commit` option. ## How to test it Setup a valid Elastic Cloud API key for QA environment: 1. Navigate to QA environment. 2. Click on the `User menu button` located on the top right of the header. 3. Click on `Organization`. 4. Click on the `API keys` tab. 5. Click on `Create API key` button. 6. Add a name, set an expiration date, assign an organization owner role. 7. Click on `Create API key` 8. Save the value of the key Store the saved key on `~/.elastic/cloud.json` using the following format: ```json { "api_key": { "qa": "" } } ``` Store the email and password of the account you used to login in the QA Environment at the root directory of your Kibana project on `.ftr/role_users.json`, using the following format: ```json { "admin": { "email": "", "password": "" } } ``` From the `x-pack/test/security_solution_cypress` you can execute the following command making sure that the commit you want to use has an available image already. In order to check for the existance of an image check: https://container-library.elastic.co/r/kibana-ci, if the image with the commit you want to use does not exist **DON'T USE THE COMMIT FLAG SINCE YOU MAY CAUSE A MAJOR ISSUE IN CONTROL PLANE > CAUSE A BULK OF ALERTS IN CONTROL PLANE** and the project will not be functional. ```cli yarn cypress:open:qa:serverless --commit ``` --- .../run_cypress/parallel_serverless.ts | 24 +++++++++++++++---- .../cypress/README.md | 22 ++++++++++++++--- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/security_solution/scripts/run_cypress/parallel_serverless.ts b/x-pack/plugins/security_solution/scripts/run_cypress/parallel_serverless.ts index d4fa3866402e6..d9418b81b538d 100644 --- a/x-pack/plugins/security_solution/scripts/run_cypress/parallel_serverless.ts +++ b/x-pack/plugins/security_solution/scripts/run_cypress/parallel_serverless.ts @@ -100,7 +100,8 @@ const getApiKeyFromElasticCloudJsonFile = (): string | undefined => { async function createSecurityProject( projectName: string, apiKey: string, - productTypes: ProductType[] + productTypes: ProductType[], + commit: string ): Promise { const body: CreateProjectRequestBody = { name: projectName, @@ -110,10 +111,12 @@ async function createSecurityProject( log.info(`Kibana override flag equals to ${process.env.KIBANA_MKI_USE_LATEST_COMMIT}!`); if ( - process.env.KIBANA_MKI_USE_LATEST_COMMIT && - process.env.KIBANA_MKI_USE_LATEST_COMMIT === '1' + (process.env.KIBANA_MKI_USE_LATEST_COMMIT && + process.env.KIBANA_MKI_USE_LATEST_COMMIT === '1') || + commit ) { - const kibanaOverrideImage = `${process.env.BUILDKITE_COMMIT?.substring(0, 12)}`; + const override = commit ? commit : process.env.BUILDKITE_COMMIT; + const kibanaOverrideImage = `${override?.substring(0, 12)}`; log.info( `Overriding Kibana image in the MKI with docker.elastic.co/kibana-ci/kibana-serverless:sec-sol-qg-${kibanaOverrideImage}` ); @@ -446,6 +449,11 @@ export const cli = () => { alias: 'ca', type: 'boolean', default: true, + }) + .option('commit', { + alias: 'c', + type: 'string', + default: '', }); log.info(` @@ -472,6 +480,7 @@ ${JSON.stringify(argv, null, 2)} const tier: string = argv.tier; const endpointAddon: boolean = argv.endpointAddon; const cloudAddon: boolean = argv.cloudAddon; + const commit: string = argv.commit; log.info(` ---------------------------------------------- @@ -557,7 +566,12 @@ ${JSON.stringify(cypressConfigFile, null, 2)} log.info(`${id}: Creating project ${PROJECT_NAME}...`); // Creating project for the test to run - const project = await createSecurityProject(PROJECT_NAME, API_KEY, productTypes); + const project = await createSecurityProject( + PROJECT_NAME, + API_KEY, + productTypes, + commit + ); if (!project) { log.info('Failed to create project.'); diff --git a/x-pack/test/security_solution_cypress/cypress/README.md b/x-pack/test/security_solution_cypress/cypress/README.md index dea0f72240d1a..d7ec660e1b24d 100644 --- a/x-pack/test/security_solution_cypress/cypress/README.md +++ b/x-pack/test/security_solution_cypress/cypress/README.md @@ -303,7 +303,10 @@ For test developing or test debugging purposes, you need to modify the configura ### Running serverless tests locally pointing to a MKI project created in QA environment (Second Quality Gate) -Run the tests with the following yarn scripts from `x-pack/test/security_solution_cypress`: +Note that when using any of the below scripts, the tests are going to be executed through an MKI project with the version that is currently available in QA. If you need to use +a specific commit (i.e. debugging a failing tests on the periodic pipeline), check the section: `Running serverless tests locally pointing to a MKI project created in QA environment with an overridden image`. + +Run the tests with the following yarn scripts from `x-pack/test/security_solution_cypress`: | Script Name | Description | | ----------- | ----------- | @@ -312,9 +315,9 @@ Run the tests with the following yarn scripts from `x-pack/test/security_solutio | cypress:run:qa:serverless:explore | Runs all tests tagged as SERVERLESS in the `e2e/explore` directory in headless mode using the QA environment and real MKI prorjects. | | cypress:run:qa:serverless:investigations | Runs all tests tagged as SERVERLESS in the `e2e/investigations` directory in headless mode using the QA environment and reak MKI projects. | | cypress:run:qa:serverless:rule_management | Runs all tests tagged as SERVERLESS in the `e2e/detection_response/rule_management` directory, excluding `e2e/detection_response/rule_management/prebuilt_rules` in headless mode using the QA environment and reak MKI projects. | -| cypress:run:qa:serverless:rule_management:prebuilt_rules | Runs all tests tagged as SERVERLESS in the `e2e/detection_response/rule_management/prebuilt_rules` directory in headless mode using the QA environment and reak MKI projects. | +| cypress:run:qa:serverless:rule_management:prebuilt_rules | Runs all tests tagged as SERVERLESS in the `e2e/detection_response/rule_management/prebuilt_rules` directory in headless mode using the QA environment and real MKI projects. | | cypress:run:qa:serverless:detection_engine | Runs all tests tagged as SERVERLESS in the `e2e/detection_response/detection_engine` directory, excluding `e2e/detection_response/detection_engine/exceptions` in headless mode using the QA environment and reak MKI projects. | -| cypress:run:qa:serverless:detection_engine:prebuilt_rules | Runs all tests tagged as SERVERLESS in the `e2e/detection_response/detection_engine/exceptions` directory in headless mode using the QA environment and reak MKI projects. | +| cypress:run:qa:serverless:detection_engine:prebuilt_rules | Runs all tests tagged as SERVERLESS in the `e2e/detection_response/detection_engine/exceptions` directory in headless mode using the QA environment and real MKI projects. | | cypress:run:qa:serverless:ai_assistant | Runs all tests tagged as SERVERLESS in the `e2e/ai_assistant` directory in headless mode using the QA environment and reak MKI projects. | @@ -355,6 +358,19 @@ Store the email and password of the account you used to login in the QA Environm } ``` +### Running serverless tests locally pointing to a MKI project created in QA environment with an overridden image + +In order to execute Cypress using a project wih an overridden image, you need to first make sure that the image is created (if you need to debug a failing test of the periodic pipeline, the image is already created you just need to check the commit that was used). + +In order to check for the existance of an image check: https://container-library.elastic.co/r/kibana-ci, if the image with the commit you want to use does not exist **DON'T USE THE COMMIT FLAG SINCE YOU MAY CAUSE A MAJOR ISSUE IN CONTROL PLANE > CAUSE A BULK OF ALERTS IN CONTROL PLANE** and the project will not be functional. + +You need to have everything setup as mentioned above in `Setup required`. Once the setup is ready you just need to execute Cypress with the following option: + +``` +yarn cypress:open:qa:serverless --commit +``` + + #### Testing with different roles If you want to execute a test using Cypress on visual mode with MKI, you need to make sure you have the user created in your organization, and add it tot he `.ftr/role_users.json`: From 083ef155f47388b5a80165fa079d652e62c376a0 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Tue, 9 Apr 2024 18:05:02 +0300 Subject: [PATCH 18/29] fix: [Rules > Create new rule][SCREEN READER]: Cursor must not get trapped in custom interface elements (#179689) Closes: https://github.com/elastic/security-team/issues/8652 ## Description The Create new rule form has a custom UI component for setting a timeline template that is trapping screen readers. The only way to escape this element is to turn off the screen reader and press the `TAB` key. This was verified in VoiceOver, NVDA, and JAWS using their preferred browsers. This issue also affects keyboard users, so it's blocker for a significant number of users to create a new rule. ### Steps to recreate 1. Open [Create new rule](https://kibana.siem.estc.dev/app/security/rules/create) 2. Open the screen reader of your choice 3. Navigate through Step 1 using the native screen reader traversal method (arrow keys or `Ctrl + Opt + ARROW`) instead of the `TAB` key as a keyboard user would 4. Verify the inability to close the Timeline Template input even when pressing `ESC` or `TAB` ### What was done?: 1. [components/timeline/search_or_filter/super_select.tsx](https://github.com/elastic/kibana/pull/179689/files#diff-2bfe78c53eba5ea9275663cd898e4c1bbcecf859ed3cd6aa39fdc5dc9464df17) It was removed as it is not used anymore. 2. The `readOnly` attribute has been removed from the `EuiFieldText` element. 3. `onFocus` has been replaced with `onKeyDown` to correctly support keyboard navigation. ### Screen https://github.com/elastic/kibana/assets/20072247/d94d884a-f54c-4aad-ac0f-0b6f201be66b --- .../search_or_filter/super_select.tsx | 273 ------------------ .../timeline/search_super_select/index.tsx | 23 +- 2 files changed, 18 insertions(+), 278 deletions(-) delete mode 100644 x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/super_select.tsx diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/super_select.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/super_select.tsx deleted file mode 100644 index e26d8339a2134..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/super_select.tsx +++ /dev/null @@ -1,273 +0,0 @@ -/* - * 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. - */ - -/* - Duplicated EuiSuperSelect, because due to the recent changes there is no way to pass panelClassName - prop to EuiInputPopover, which doesn't allow us to properly style the EuiInputPopover panel - (we want the panel to be wider than the input) -*/ - -import type { EuiSuperSelectProps } from '@elastic/eui'; -import { - EuiScreenReaderOnly, - EuiSuperSelectControl, - EuiInputPopover, - EuiContextMenuItem, - keys, - EuiI18n, -} from '@elastic/eui'; -import React, { Component } from 'react'; -import classNames from 'classnames'; - -enum ShiftDirection { - BACK = 'back', - FORWARD = 'forward', -} - -export class EuiSuperSelect extends Component> { - static defaultProps = { - compressed: false, - fullWidth: false, - hasDividers: false, - isInvalid: false, - isLoading: false, - }; - - private itemNodes: Array = []; - private _isMounted: boolean = false; - - state = { - isPopoverOpen: this.props.isOpen || false, - }; - - componentDidMount() { - this._isMounted = true; - if (this.props.isOpen) { - this.openPopover(); - } - } - - componentWillUnmount() { - this._isMounted = false; - } - - setItemNode = (node: HTMLButtonElement | null, index: number) => { - this.itemNodes[index] = node; - }; - - openPopover = () => { - this.setState({ - isPopoverOpen: true, - }); - - const focusSelected = () => { - const indexOfSelected = this.props.options.reduce((acc, option, index) => { - if (acc != null) return acc; - if (option == null) return null; - return option.value === this.props.valueOfSelected ? index : null; - }, null); - - requestAnimationFrame(() => { - if (!this._isMounted) { - return; - } - - if (this.props.valueOfSelected != null) { - if (indexOfSelected != null) { - this.focusItemAt(indexOfSelected); - } else { - focusSelected(); - } - } - }); - }; - - requestAnimationFrame(focusSelected); - }; - - closePopover = () => { - this.setState({ - isPopoverOpen: false, - }); - }; - - itemClicked = (value: T) => { - this.setState({ - isPopoverOpen: false, - }); - if (this.props.onChange) { - this.props.onChange(value); - } - }; - - onSelectKeyDown = (event: React.KeyboardEvent) => { - if (event.key === keys.ARROW_UP || event.key === keys.ARROW_DOWN) { - event.preventDefault(); - event.stopPropagation(); - this.openPopover(); - } - }; - - onItemKeyDown = (event: React.KeyboardEvent) => { - switch (event.key) { - case keys.ESCAPE: - // close the popover and prevent ancestors from handling - event.preventDefault(); - event.stopPropagation(); - this.closePopover(); - break; - - case keys.TAB: - // no-op - event.preventDefault(); - event.stopPropagation(); - break; - - case keys.ARROW_UP: - event.preventDefault(); - event.stopPropagation(); - this.shiftFocus(ShiftDirection.BACK); - break; - - case keys.ARROW_DOWN: - event.preventDefault(); - event.stopPropagation(); - this.shiftFocus(ShiftDirection.FORWARD); - break; - } - }; - - focusItemAt(index: number) { - const targetElement = this.itemNodes[index]; - if (targetElement != null) { - targetElement.focus(); - } - } - - shiftFocus(direction: ShiftDirection) { - const currentIndex = this.itemNodes.indexOf(document.activeElement as HTMLButtonElement); - let targetElementIndex: number; - - if (currentIndex === -1) { - // somehow the select options has lost focus - targetElementIndex = 0; - } else { - if (direction === ShiftDirection.BACK) { - targetElementIndex = currentIndex === 0 ? this.itemNodes.length - 1 : currentIndex - 1; - } else { - targetElementIndex = currentIndex === this.itemNodes.length - 1 ? 0 : currentIndex + 1; - } - } - - this.focusItemAt(targetElementIndex); - } - - render() { - const { - className, - options, - valueOfSelected, - onChange, - isOpen, - isInvalid, - hasDividers, - itemClassName, - itemLayoutAlign, - fullWidth, - popoverProps, - compressed, - ...rest - } = this.props; - - const popoverClasses = classNames('euiSuperSelect', popoverProps?.className); - - const buttonClasses = classNames( - { - 'euiSuperSelect--isOpen__button': this.state.isPopoverOpen, - }, - className - ); - - const itemClasses = classNames( - 'euiSuperSelect__item', - { - 'euiSuperSelect__item--hasDividers': hasDividers, - }, - itemClassName - ); - - const button = ( - - ); - - const items = options.map((option, index) => { - const { value, dropdownDisplay, inputDisplay, ...optionRest } = option; - - return ( - this.itemClicked(value)} - onKeyDown={this.onItemKeyDown} - layoutAlign={itemLayoutAlign} - buttonRef={(node) => this.setItemNode(node, index)} - role="option" - id={value} - aria-selected={valueOfSelected === value} - {...optionRest} - > - {dropdownDisplay || inputDisplay} - - ); - }); - - return ( - - -

- -

-
-
- {items} -
-
- ); - } -} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_super_select/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_super_select/index.tsx index 7289f32fca36e..c1927579f8019 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_super_select/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_super_select/index.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import type { EuiSelectableOption } from '@elastic/eui'; -import { EuiInputPopover, EuiFieldText, htmlIdGenerator } from '@elastic/eui'; +import type { EuiSelectableOption, EuiFieldTextProps } from '@elastic/eui'; +import { EuiInputPopover, EuiFieldText, htmlIdGenerator, keys } from '@elastic/eui'; import React, { memo, useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; @@ -90,15 +90,20 @@ const SearchTimelineSuperSelectComponent: React.FC { + if (event.key === keys.ENTER) { + setIsPopoverOpen(true); + } + }, []); + const popoverId = useMemo(() => htmlIdGenerator('searchTimelinePopover')(), []); const superSelect = useMemo( () => ( ), - [ariaLabel, handleOpenPopover, isDisabled, isPopoverOpen, popoverId, timelineTitle] + [ + ariaLabel, + handleKeyboardOpen, + handleOpenPopover, + isDisabled, + isPopoverOpen, + popoverId, + timelineTitle, + ] ); const handleGetSelectableOptions = useCallback( From de6d2ba61a8f39fe695bb8c1c81881964658b4fa Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Tue, 9 Apr 2024 18:05:21 +0300 Subject: [PATCH 19/29] fix: [Dashboard][SCREEN READER]: Headings must be properly nested for usability (#180191) Closes: https://github.com/elastic/security-team/issues/8637 Closes: https://github.com/elastic/security-team/issues/8693 Closes: https://github.com/elastic/security-team/issues/8639 Closes: https://github.com/elastic/security-team/issues/8638 ### What was done? 1. `h4` was changed to `h2` for `header-section-title` 2. `Hidden` `h1` was added for Dashboard Overview page ### Screens #### https://github.com/elastic/security-team/issues/8637 ![image](https://github.com/elastic/kibana/assets/20072247/3d5409bd-0cf3-4a31-a565-ecf5851ff889) #### https://github.com/elastic/security-team/issues/8693 : ![image](https://github.com/elastic/kibana/assets/20072247/b7bad8f9-7998-4791-9e16-af3f47a9f316) #### https://github.com/elastic/security-team/issues/8639 ![image](https://github.com/elastic/kibana/assets/20072247/c37e111e-90f6-492d-818e-52adedbe1345) ### https://github.com/elastic/security-team/issues/8638 ![image](https://github.com/elastic/kibana/assets/20072247/914af668-e35f-4f24-90f4-d5d0cf6f5f22) --- .../__snapshots__/index.test.tsx.snap | 4 ++-- .../common/components/header_section/index.tsx | 4 ++-- .../authentications_host_table.test.tsx.snap | 4 ++-- .../authentications_user_table.test.tsx.snap | 4 ++-- .../public/overview/pages/overview.tsx | 13 ++++++++++++- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/components/header_section/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/header_section/__snapshots__/index.test.tsx.snap index 46c33d5102feb..3ef2ecf88449b 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_section/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/header_section/__snapshots__/index.test.tsx.snap @@ -39,7 +39,7 @@ exports[`HeaderSection it renders 1`] = ` -

Test title -

+
diff --git a/x-pack/plugins/security_solution/public/common/components/header_section/index.tsx b/x-pack/plugins/security_solution/public/common/components/header_section/index.tsx index 70c6e6778a604..75cd089a87e36 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_section/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/header_section/index.tsx @@ -169,7 +169,7 @@ const HeaderSectionComponent: React.FC = ({ )} -

+

{title} {tooltip && ( <> @@ -182,7 +182,7 @@ const HeaderSectionComponent: React.FC = ({ /> )} -

+
diff --git a/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_host_table.test.tsx.snap b/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_host_table.test.tsx.snap index b0b2754c24d3b..bf74c41fa303f 100644 --- a/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_host_table.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_host_table.test.tsx.snap @@ -104,7 +104,7 @@ exports[`Authentication Host Table Component rendering it renders the host authe
-

@@ -113,7 +113,7 @@ exports[`Authentication Host Table Component rendering it renders the host authe > Authentications -

+
diff --git a/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_user_table.test.tsx.snap b/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_user_table.test.tsx.snap index 3d31cd3759ffe..4acce15364b6b 100644 --- a/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_user_table.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_user_table.test.tsx.snap @@ -104,7 +104,7 @@ exports[`Authentication User Table Component rendering it renders the user authe
-

@@ -113,7 +113,7 @@ exports[`Authentication User Table Component rendering it renders the user authe > Authentications -

+
diff --git a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx index e91a7487f6491..c10fab09fa47b 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx @@ -5,9 +5,16 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiShowFor } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiShowFor, + EuiScreenReaderOnly, +} from '@elastic/eui'; import React, { useCallback, useState, useMemo } from 'react'; +import { OVERVIEW } from '../../app/translations'; import { InputsModelId } from '../../common/store/inputs/constants'; import { FiltersGlobal } from '../../common/components/filters_global'; import { SiemSearchBar } from '../../common/components/search_bar'; @@ -69,6 +76,10 @@ const OverviewComponent = () => { return ( <> + +

{OVERVIEW}

+
+ {indicesExist ? ( <> From 49777dc232ca7b1adfd923903fd6751c8898b656 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Tue, 9 Apr 2024 17:12:46 +0200 Subject: [PATCH 20/29] Moves ES|QL out of Technical preview (GA) (#178860) ## Summary Moves ES|QL out of Technical preview (GA) which means that: - Removes tech preview badge from unified search - Removes tech preview callout from Discover - Removes tech preview badge from inline editing flyout (I am keeping it to indicate the inline editing is still on tech preview but I am removing the specific ES|QL message - Removes tech preview text from advanced setting --- .../components/layout/discover_layout.tsx | 5 -- .../layout/esql_tech_preview_callout.tsx | 55 ------------------- src/plugins/discover/server/ui_settings.ts | 7 +-- .../dataview_picker/change_dataview.tsx | 6 -- .../shared/edit_on_the_fly/flyout_wrapper.tsx | 16 ++---- .../translations/translations/fr-FR.json | 18 ++---- .../translations/translations/ja-JP.json | 6 -- .../translations/translations/zh-CN.json | 6 -- 8 files changed, 11 insertions(+), 108 deletions(-) delete mode 100644 src/plugins/discover/public/application/main/components/layout/esql_tech_preview_callout.tsx diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx index 41a05a18da62b..344e0b36c9d0e 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx @@ -51,7 +51,6 @@ import { DiscoverHistogramLayout } from './discover_histogram_layout'; import { ErrorCallout } from '../../../../components/common/error_callout'; import { addLog } from '../../../../utils/add_log'; import { DiscoverResizableLayout } from './discover_resizable_layout'; -import { ESQLTechPreviewCallout } from './esql_tech_preview_callout'; import { PanelsToggle, PanelsToggleProps } from '../../../../components/panels_toggle'; import { sendErrorMsg } from '../../hooks/use_saved_search_messages'; @@ -72,7 +71,6 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { filterManager, history, spaces, - docLinks, } = useDiscoverServices(); const pageBackgroundColor = useEuiBackgroundColor('plain'); const globalQueryState = data.query.getState(); @@ -219,8 +217,6 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { return ( <> - {/* Temporarily display a tech preview callout for ES|QL*/} - {isPlainRecord && } { - const [hideCallout, setHideCallout] = useLocalStorage(ESQL_TECH_PREVIEW_CALLOUT, false); - - const onDismiss = useCallback(() => { - setHideCallout(true); - }, [setHideCallout]); - - if (hideCallout) { - return null; - } - - return ( - - - - ), - }} - /> - } - color="primary" - iconType="beaker" - onDismiss={onDismiss} - size="s" - /> - ); -}; diff --git a/src/plugins/discover/server/ui_settings.ts b/src/plugins/discover/server/ui_settings.ts index 806ae826bf3ab..096869d18ca51 100644 --- a/src/plugins/discover/server/ui_settings.ts +++ b/src/plugins/discover/server/ui_settings.ts @@ -34,10 +34,6 @@ import { } from '@kbn/discover-utils'; import { DEFAULT_ROWS_PER_PAGE, ROWS_PER_PAGE_OPTIONS } from '../common/constants'; -const technicalPreviewLabel = i18n.translate('discover.advancedSettings.technicalPreviewLabel', { - defaultMessage: 'technical preview', -}); - export const getUiSettings: ( docLinks: DocLinksServiceSetup, enableValidations: boolean @@ -321,7 +317,7 @@ export const getUiSettings: ( value: true, description: i18n.translate('discover.advancedSettings.enableESQLDescription', { defaultMessage: - '{technicalPreviewLabel} This tech preview feature is highly experimental--do not rely on this for production saved searches, visualizations or dashboards. This setting enables ES|QL in Discover. If you have feedback on this experience please reach out to us on {link}', + 'This setting enables ES|QL in Discover. If you have feedback on this experience please reach out to us on {link}', values: { link: `` + @@ -329,7 +325,6 @@ export const getUiSettings: ( defaultMessage: 'discuss.elastic.co/c/elastic-stack/kibana', }) + '', - technicalPreviewLabel: `[${technicalPreviewLabel}]`, }, }), requiresPageReload: true, diff --git a/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx b/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx index eb75d3486d5d5..e9d8058ff1420 100644 --- a/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx +++ b/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx @@ -12,7 +12,6 @@ import { css } from '@emotion/react'; import { EuiPopover, EuiPanel, - EuiBadge, EuiHorizontalRule, EuiButton, EuiContextMenuPanel, @@ -361,11 +360,6 @@ export function ChangeDataView({ {i18n.translate('unifiedSearch.query.queryBar.textBasedLanguagesTryLabel', { defaultMessage: 'Try ES|QL', })} - - {i18n.translate('unifiedSearch.query.queryBar.textBasedLanguagesTechPreviewLabel', { - defaultMessage: 'Technical preview', - })} -
); diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/flyout_wrapper.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/flyout_wrapper.tsx index f8ee1c5779693..3c013cdc95998 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/flyout_wrapper.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/flyout_wrapper.tsx @@ -62,18 +62,10 @@ export const FlyoutWrapper = ({ values: { lang: language }, })} Date: Tue, 9 Apr 2024 16:13:44 +0100 Subject: [PATCH 21/29] skip flaky suite (#171665) --- .../cypress/e2e/automated_response_actions/results.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/results.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/results.cy.ts index 344c4b0b3bd21..c818599d06410 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/results.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/results.cy.ts @@ -14,7 +14,8 @@ import { indexEndpointRuleAlerts } from '../../tasks/index_endpoint_rule_alerts' import { login, ROLE } from '../../tasks/login'; -describe('Results', { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/171665 +describe.skip('Results', { tags: ['@ess', '@serverless'] }, () => { let endpointData: ReturnTypeFromChainable | undefined; let alertData: ReturnTypeFromChainable | undefined; const [endpointAgentId, endpointHostname] = generateRandomStringName(2); From f427c2522de7f6acd23027c7c07751887edd1060 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 9 Apr 2024 16:21:49 +0100 Subject: [PATCH 22/29] skip flaky suite (#170357) --- .../security_solution_endpoint/apps/endpoint/endpoint_list.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts index 6f9c89bd8c930..e4d9b91e579b7 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts @@ -87,7 +87,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // FLAKY: https://github.com/elastic/kibana/issues/170357 // FLAKY: https://github.com/elastic/kibana/issues/173670 - describe('endpoint list', function () { + describe.skip('endpoint list', function () { targetTags(this, ['@ess', '@serverless']); let indexedData: IndexedHostsAndAlertsResponse; From 4b690837c295a9e6dcaa343fe5f62b9ba0d2136c Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 9 Apr 2024 16:27:22 +0100 Subject: [PATCH 23/29] skip flaky suite (#171666) --- .../apis/endpoint_response_actions/execute.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts index 1234c45f9210f..f8019154206e0 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts @@ -16,7 +16,8 @@ export default function ({ getService }: FtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); const endpointTestResources = getService('endpointTestResources'); - describe('Endpoint `execute` response action', function () { + // FLAKY: https://github.com/elastic/kibana/issues/171666 + describe.skip('Endpoint `execute` response action', function () { targetTags(this, ['@ess', '@serverless']); let indexedData: IndexedHostsAndAlertsResponse; From 125c8951e575bcd151317e4ba646a3f5f904b5cc Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Tue, 9 Apr 2024 17:39:08 +0200 Subject: [PATCH 24/29] [ES|QL] Runs the _query requests with the version (#180248) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Due to https://github.com/elastic/kibana/issues/179641 ES is going to add a mandatory field `version`. (it is optional for now but they want to make it required for the GA). The version will change in backwards incompatible changes: - syntax changes - functions / commands output changes This is the first PR which is adding the first version manually for now. In https://github.com/elastic/kibana/issues/179641 we are exploring how to deal with versioning in kibana. We are going to offer a solution in 8.15. For now we are adding the version hardcoded (otherwise when the field is marked required kibana _query requests will fail. 👮‍♀️ If you are aware of any other application which uses the _query api and is not updated in this PR please let me know --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- packages/kbn-es-types/src/search.ts | 1 + packages/kbn-esql-utils/constants.ts | 11 +++++++++++ packages/kbn-esql-utils/index.ts | 2 ++ .../kbn-generate-csv/src/generate_csv_esql.test.ts | 6 ++++-- packages/kbn-generate-csv/src/generate_csv_esql.ts | 3 ++- packages/kbn-generate-csv/tsconfig.json | 1 + .../load_field_stats_text_based.ts | 3 ++- src/plugins/data/common/search/expressions/esql.ts | 2 ++ .../esql_async_search_strategy.test.ts | 12 +++++++++++- src/plugins/data/tsconfig.json | 3 ++- test/api_integration/apis/esql/errors.ts | 2 ++ test/tsconfig.json | 1 + .../hooks/esql/use_esql_overall_stats_data.ts | 5 ++++- .../esql_requests/get_count_and_cardinality.ts | 2 ++ .../esql_requests/get_date_field_stats.ts | 2 ++ .../esql_requests/get_numeric_field_stats.ts | 2 ++ .../esql_requests/get_text_field_stats.ts | 2 ++ .../classes/sources/esql_source/esql_source.tsx | 7 ++++++- .../server/functions/query/index.ts | 2 ++ .../server/functions/visualize_esql.ts | 2 ++ .../rule_types/esql/build_esql_search_request.ts | 2 ++ .../rule_types/es_query/lib/fetch_esql_query.test.ts | 2 ++ .../rule_types/es_query/lib/fetch_esql_query.ts | 2 ++ 23 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 packages/kbn-esql-utils/constants.ts diff --git a/packages/kbn-es-types/src/search.ts b/packages/kbn-es-types/src/search.ts index 43fbe15586090..f9f304914afaa 100644 --- a/packages/kbn-es-types/src/search.ts +++ b/packages/kbn-es-types/src/search.ts @@ -678,6 +678,7 @@ export interface ESQLSearchParams { // https://github.com/elastic/elasticsearch/pull/102767 // time_zone?: string; query: string; + version: string; filter?: unknown; locale?: string; dropNullColumns?: boolean; diff --git a/packages/kbn-esql-utils/constants.ts b/packages/kbn-esql-utils/constants.ts new file mode 100644 index 0000000000000..51dcbab83654b --- /dev/null +++ b/packages/kbn-esql-utils/constants.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. + */ + +// we are expecting to retrieve this from an API instead +// https://github.com/elastic/elasticsearch/issues/107069 +export const ESQL_LATEST_VERSION = '2024.04.01'; diff --git a/packages/kbn-esql-utils/index.ts b/packages/kbn-esql-utils/index.ts index 1592777d136f3..885c491986582 100644 --- a/packages/kbn-esql-utils/index.ts +++ b/packages/kbn-esql-utils/index.ts @@ -17,3 +17,5 @@ export { getESQLWithSafeLimit, TextBasedLanguages, } from './src'; + +export { ESQL_LATEST_VERSION } from './constants'; diff --git a/packages/kbn-generate-csv/src/generate_csv_esql.test.ts b/packages/kbn-generate-csv/src/generate_csv_esql.test.ts index 3e925893d37e4..ee514788c72cf 100644 --- a/packages/kbn-generate-csv/src/generate_csv_esql.test.ts +++ b/packages/kbn-generate-csv/src/generate_csv_esql.test.ts @@ -22,6 +22,7 @@ import { IKibanaSearchResponse } from '@kbn/data-plugin/common'; import { IScopedSearchClient } from '@kbn/data-plugin/server'; import { dataPluginMock } from '@kbn/data-plugin/server/mocks'; import { CancellationToken } from '@kbn/reporting-common'; +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import type { ReportingConfigType } from '@kbn/reporting-server'; import type { ESQLSearchReponse as ESQLSearchResponse } from '@kbn/es-types'; import { @@ -311,7 +312,7 @@ describe('CsvESQLGenerator', () => { ); expect(mockDataClientSearchFn).toBeCalledWith( - { params: { filter: undefined, locale: 'en', query: '' } }, + { params: { filter: undefined, locale: 'en', query: '', version: ESQL_LATEST_VERSION } }, { strategy: 'esql', transport: { @@ -389,7 +390,7 @@ describe('CsvESQLGenerator', () => { ); expect(mockDataClientSearchFn).toBeCalledWith( - { params: { filter: undefined, locale: 'en', query: '' } }, + { params: { filter: undefined, locale: 'en', query: '', version: ESQL_LATEST_VERSION } }, { strategy: 'esql', transport: { @@ -485,6 +486,7 @@ describe('CsvESQLGenerator', () => { }, locale: 'en', query: '', + version: ESQL_LATEST_VERSION, }, }, { diff --git a/packages/kbn-generate-csv/src/generate_csv_esql.ts b/packages/kbn-generate-csv/src/generate_csv_esql.ts index cea0838460ab5..dbfe073ff62f3 100644 --- a/packages/kbn-generate-csv/src/generate_csv_esql.ts +++ b/packages/kbn-generate-csv/src/generate_csv_esql.ts @@ -8,7 +8,7 @@ import { lastValueFrom } from 'rxjs'; import type { Writable } from 'stream'; - +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import { errors as esErrors } from '@elastic/elasticsearch'; import type { IScopedClusterClient, IUiSettingsClient, Logger } from '@kbn/core/server'; import { @@ -100,6 +100,7 @@ export class CsvESQLGenerator { // we will need to add it back in once it is supported again. // https://github.com/elastic/elasticsearch/pull/102767 // timezone + version: ESQL_LATEST_VERSION, }, }; diff --git a/packages/kbn-generate-csv/tsconfig.json b/packages/kbn-generate-csv/tsconfig.json index 6db6b731929a1..ce90e0fc346d5 100644 --- a/packages/kbn-generate-csv/tsconfig.json +++ b/packages/kbn-generate-csv/tsconfig.json @@ -28,5 +28,6 @@ "@kbn/reporting-export-types-csv-common", "@kbn/es-query", "@kbn/es-types", + "@kbn/esql-utils", ] } diff --git a/packages/kbn-unified-field-list/src/services/field_stats_text_based/load_field_stats_text_based.ts b/packages/kbn-unified-field-list/src/services/field_stats_text_based/load_field_stats_text_based.ts index 347bdba723808..7d63c02633e77 100644 --- a/packages/kbn-unified-field-list/src/services/field_stats_text_based/load_field_stats_text_based.ts +++ b/packages/kbn-unified-field-list/src/services/field_stats_text_based/load_field_stats_text_based.ts @@ -15,7 +15,7 @@ import type { } from '@kbn/data-plugin/public'; import type { ESQLSearchParams, ESQLSearchReponse } from '@kbn/es-types'; import type { AggregateQuery } from '@kbn/es-query'; -import { getESQLWithSafeLimit } from '@kbn/esql-utils'; +import { ESQL_LATEST_VERSION, getESQLWithSafeLimit } from '@kbn/esql-utils'; import type { FieldStatsResponse } from '../../types'; import { buildSearchFilter, @@ -77,6 +77,7 @@ export const loadFieldStatsTextBased: LoadFieldStatsTextBasedHandler = async ({ params: { ...(filter ? { filter } : {}), ...body, + version: ESQL_LATEST_VERSION, }, }, { diff --git a/src/plugins/data/common/search/expressions/esql.ts b/src/plugins/data/common/search/expressions/esql.ts index 7ed11099c4bef..d9893c8c203f6 100644 --- a/src/plugins/data/common/search/expressions/esql.ts +++ b/src/plugins/data/common/search/expressions/esql.ts @@ -17,6 +17,7 @@ import { Observable, defer, throwError } from 'rxjs'; import { catchError, map, switchMap, tap } from 'rxjs'; import { buildEsQuery } from '@kbn/es-query'; import type { ESQLSearchReponse, ESQLSearchParams } from '@kbn/es-types'; +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import { getEsQueryConfig } from '../../es_query'; import { getTime } from '../../query'; import { @@ -130,6 +131,7 @@ export const getEsqlFn = ({ getStartDependencies }: EsqlFnArguments) => { query, // time_zone: timezone, locale, + version: ESQL_LATEST_VERSION, }; if (input) { const esQueryConfigs = getEsQueryConfig( diff --git a/src/plugins/data/server/search/strategies/esql_async_search/esql_async_search_strategy.test.ts b/src/plugins/data/server/search/strategies/esql_async_search/esql_async_search_strategy.test.ts index b88683157db03..b1e36954e0b67 100644 --- a/src/plugins/data/server/search/strategies/esql_async_search/esql_async_search_strategy.test.ts +++ b/src/plugins/data/server/search/strategies/esql_async_search/esql_async_search_strategy.test.ts @@ -8,6 +8,7 @@ import { firstValueFrom } from 'rxjs'; import { KbnServerError } from '@kbn/kibana-utils-plugin/server'; +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import { KbnSearchError } from '../../report_search_error'; import { errors } from '@elastic/elasticsearch'; import indexNotFoundException from '../../../../common/search/test_data/index_not_found_exception.json'; @@ -66,6 +67,7 @@ describe('ES|QL async search strategy', () => { const esSearch = await esqlAsyncSearchStrategyProvider(mockSearchConfig, mockLogger); const params = { query: 'from logs* | limit 10', + version: ESQL_LATEST_VERSION, }; await esSearch .search( @@ -89,6 +91,7 @@ describe('ES|QL async search strategy', () => { const params = { query: 'from logs* | limit 10', + version: ESQL_LATEST_VERSION, }; const esSearch = await esqlAsyncSearchStrategyProvider(mockSearchConfig, mockLogger); @@ -108,6 +111,7 @@ describe('ES|QL async search strategy', () => { query: 'from logs* | limit 10', wait_for_completion_timeout: '10s', keep_alive: '5m', + version: ESQL_LATEST_VERSION, }; const esSearch = await esqlAsyncSearchStrategyProvider(mockSearchConfig, mockLogger); @@ -123,7 +127,7 @@ describe('ES|QL async search strategy', () => { it('sets transport options on POST requests', async () => { const transportOptions = { maxRetries: 1 }; mockApiCaller.mockResolvedValueOnce(mockAsyncResponse); - const params = { query: 'from logs' }; + const params = { query: 'from logs', version: ESQL_LATEST_VERSION }; const esSearch = esqlAsyncSearchStrategyProvider(mockSearchConfig, mockLogger); await firstValueFrom( @@ -140,6 +144,7 @@ describe('ES|QL async search strategy', () => { wait_for_completion_timeout: '100ms', keep_on_completion: false, query: 'from logs', + version: ESQL_LATEST_VERSION, }, }), expect.objectContaining({ maxRetries: 1, meta: true, signal: undefined }) @@ -150,6 +155,7 @@ describe('ES|QL async search strategy', () => { mockApiCaller.mockResolvedValueOnce(mockAsyncResponse); const params = { query: 'from logs* | limit 10', + version: ESQL_LATEST_VERSION, }; const esSearch = esqlAsyncSearchStrategyProvider(mockSearchConfig, mockLogger); @@ -175,6 +181,7 @@ describe('ES|QL async search strategy', () => { const params = { query: 'from logs* | limit 10', + version: ESQL_LATEST_VERSION, }; const esSearch = await esqlAsyncSearchStrategyProvider(mockSearchConfig, mockLogger); @@ -197,6 +204,7 @@ describe('ES|QL async search strategy', () => { const params = { query: 'from logs* | limit 10', + version: ESQL_LATEST_VERSION, }; const esSearch = await esqlAsyncSearchStrategyProvider(mockSearchConfig, mockLogger); const abortController = new AbortController(); @@ -230,6 +238,7 @@ describe('ES|QL async search strategy', () => { const params = { query: 'from logs* | limit 10', + version: ESQL_LATEST_VERSION, }; const esSearch = await esqlAsyncSearchStrategyProvider(mockSearchConfig, mockLogger); @@ -253,6 +262,7 @@ describe('ES|QL async search strategy', () => { const params = { query: 'from logs* | limit 10', + version: ESQL_LATEST_VERSION, }; const esSearch = await esqlAsyncSearchStrategyProvider(mockSearchConfig, mockLogger); diff --git a/src/plugins/data/tsconfig.json b/src/plugins/data/tsconfig.json index 74fc83691ec53..c96442ccae5ed 100644 --- a/src/plugins/data/tsconfig.json +++ b/src/plugins/data/tsconfig.json @@ -53,7 +53,8 @@ "@kbn/bfetch-error", "@kbn/es-types", "@kbn/code-editor", - "@kbn/core-test-helpers-model-versions" + "@kbn/core-test-helpers-model-versions", + "@kbn/esql-utils" ], "exclude": [ "target/**/*", diff --git a/test/api_integration/apis/esql/errors.ts b/test/api_integration/apis/esql/errors.ts index ad4e251a8f364..9a79706a43ae3 100644 --- a/test/api_integration/apis/esql/errors.ts +++ b/test/api_integration/apis/esql/errors.ts @@ -11,6 +11,7 @@ import Path from 'path'; import expect from '@kbn/expect'; import { MappingProperty } from '@elastic/elasticsearch/lib/api/types'; import { REPO_ROOT } from '@kbn/repo-info'; +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import uniqBy from 'lodash/uniqBy'; import { groupBy, mapValues } from 'lodash'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -123,6 +124,7 @@ export default function ({ getService }: FtrProviderContext) { path: '/_query', body: { query, + version: ESQL_LATEST_VERSION, }, }); return { resp, error: undefined }; diff --git a/test/tsconfig.json b/test/tsconfig.json index c5c7467dd8bcd..ebf1a1e71c01b 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -73,5 +73,6 @@ "@kbn/links-plugin", "@kbn/ftr-common-functional-ui-services", "@kbn/monaco", + "@kbn/esql-utils", ] } diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/esql/use_esql_overall_stats_data.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/esql/use_esql_overall_stats_data.ts index 1d5e2e4626e70..3cb59da17ad8c 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/esql/use_esql_overall_stats_data.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/esql/use_esql_overall_stats_data.ts @@ -14,7 +14,7 @@ import { type UseCancellableSearch, useCancellableSearch } from '@kbn/ml-cancell import type { estypes } from '@elastic/elasticsearch'; import type { ISearchOptions } from '@kbn/data-plugin/common'; import type { TimeBucketsInterval } from '@kbn/ml-time-buckets'; -import { getESQLWithSafeLimit } from '@kbn/esql-utils'; +import { getESQLWithSafeLimit, ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import { OMIT_FIELDS } from '../../../../../common/constants'; import type { DataStatsFetchProgress, @@ -84,6 +84,7 @@ const getESQLDocumentCountStats = async ( params: { query: esqlBaseQuery + aggQuery, ...(filter ? { filter } : {}), + version: ESQL_LATEST_VERSION, }, }; try { @@ -129,6 +130,7 @@ const getESQLDocumentCountStats = async ( params: { query: esqlBaseQuery + ' | STATS _count_ = COUNT(*) | LIMIT 1', ...(filter ? { filter } : {}), + version: ESQL_LATEST_VERSION, }, }; try { @@ -247,6 +249,7 @@ export const useESQLOverallStatsData = ( params: { query: esqlBaseQuery + '| LIMIT 0', ...(filter ? { filter } : {}), + version: ESQL_LATEST_VERSION, }, }, { strategy: ESQL_SEARCH_STRATEGY } diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_count_and_cardinality.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_count_and_cardinality.ts index 41bc6e4b52b6d..9bcf5e7190fb2 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_count_and_cardinality.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_count_and_cardinality.ts @@ -9,6 +9,7 @@ import pLimit from 'p-limit'; import { chunk } from 'lodash'; import { isDefined } from '@kbn/ml-is-defined'; import type { ESQLSearchReponse } from '@kbn/es-types'; +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import type { UseCancellableSearch } from '@kbn/ml-cancellable-search'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { i18n } from '@kbn/i18n'; @@ -105,6 +106,7 @@ const getESQLOverallStatsInChunk = async ({ params: { query, ...(filter ? { filter } : {}), + version: ESQL_LATEST_VERSION, }, }; diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_date_field_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_date_field_stats.ts index fb06899466576..846aadf7e17ad 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_date_field_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_date_field_stats.ts @@ -8,6 +8,7 @@ import type { UseCancellableSearch } from '@kbn/ml-cancellable-search'; import type { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; import { ESQL_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import type { Column } from '../../hooks/esql/use_esql_overall_stats_data'; import { getSafeESQLName } from '../requests/esql_utils'; import type { DateFieldStats, FieldStatsError } from '../../../../../common/types/field_stats'; @@ -40,6 +41,7 @@ export const getESQLDateFieldStats = async ({ params: { query: esqlBaseQuery + dateStatsQuery, ...(filter ? { filter } : {}), + version: ESQL_LATEST_VERSION, }, }; try { diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_numeric_field_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_numeric_field_stats.ts index 2f0ea4d7b3070..615d07abc4066 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_numeric_field_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_numeric_field_stats.ts @@ -8,6 +8,7 @@ import type { UseCancellableSearch } from '@kbn/ml-cancellable-search'; import type { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; import { ESQL_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import { chunk } from 'lodash'; import pLimit from 'p-limit'; import type { Column } from '../../hooks/esql/use_esql_overall_stats_data'; @@ -69,6 +70,7 @@ const getESQLNumericFieldStatsInChunk = async ({ params: { query: esqlBaseQuery + numericStatsQuery, ...(filter ? { filter } : {}), + version: ESQL_LATEST_VERSION, }, }; try { diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_text_field_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_text_field_stats.ts index d78e286e88d31..f79e6fc9a7145 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_text_field_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_text_field_stats.ts @@ -8,6 +8,7 @@ import type { UseCancellableSearch } from '@kbn/ml-cancellable-search'; import type { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; import { ESQL_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import type { Column } from '../../hooks/esql/use_esql_overall_stats_data'; import type { FieldExamples, FieldStatsError } from '../../../../../common/types/field_stats'; @@ -39,6 +40,7 @@ export const getESQLExampleFieldValues = async ({ `| KEEP ${textFields.map((f) => f.name).join(',')} | LIMIT 10`, ...(filter ? { filter } : {}), + version: ESQL_LATEST_VERSION, }, }; const textFieldsResp = await runRequest(request, { strategy: ESQL_SEARCH_STRATEGY }); diff --git a/x-pack/plugins/maps/public/classes/sources/esql_source/esql_source.tsx b/x-pack/plugins/maps/public/classes/sources/esql_source/esql_source.tsx index a40e8daf79d4a..af6a60f934e82 100644 --- a/x-pack/plugins/maps/public/classes/sources/esql_source/esql_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/esql_source/esql_source.tsx @@ -11,7 +11,11 @@ import { lastValueFrom } from 'rxjs'; import { tap } from 'rxjs'; import { v4 as uuidv4 } from 'uuid'; import { Adapters } from '@kbn/inspector-plugin/common/adapters'; -import { getIndexPatternFromESQLQuery, getLimitFromESQLQuery } from '@kbn/esql-utils'; +import { + getIndexPatternFromESQLQuery, + getLimitFromESQLQuery, + ESQL_LATEST_VERSION, +} from '@kbn/esql-utils'; import { buildEsQuery } from '@kbn/es-query'; import type { Filter, Query } from '@kbn/es-query'; import type { ESQLSearchParams, ESQLSearchReponse } from '@kbn/es-types'; @@ -153,6 +157,7 @@ export class ESQLSource const params: ESQLSearchParams = { query: this._descriptor.esql, dropNullColumns: true, + version: ESQL_LATEST_VERSION, }; const query: Query[] = []; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts index 6c6df6f5e90d9..1cedf540a545a 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/query/index.ts @@ -11,6 +11,7 @@ import pLimit from 'p-limit'; import Path from 'path'; import { lastValueFrom, startWith } from 'rxjs'; import { promisify } from 'util'; +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import { FunctionVisibility, MessageRole } from '@kbn/observability-ai-assistant-plugin/common'; import { VisualizeESQLUserIntention, @@ -95,6 +96,7 @@ export function registerQueryFunction({ path: '_query', body: { query, + version: ESQL_LATEST_VERSION, }, }); diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/visualize_esql.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/visualize_esql.ts index be1e73a8039ff..d66c356997c5a 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/visualize_esql.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/visualize_esql.ts @@ -6,6 +6,7 @@ */ import { esFieldTypeToKibanaFieldType } from '@kbn/field-types'; import type { ESQLSearchReponse } from '@kbn/es-types'; +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import { VisualizeESQLUserIntention } from '@kbn/observability-ai-assistant-plugin/common/functions/visualize_esql'; import { visualizeESQLFunction } from '../../common/functions/visualize_esql'; import { FunctionRegistrationParameters } from '.'; @@ -28,6 +29,7 @@ export function registerVisualizeESQLFunction({ path: '_query', body: { query: performantQuery, + version: ESQL_LATEST_VERSION, }, })) as ESQLSearchReponse; const columns = diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/build_esql_search_request.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/build_esql_search_request.ts index 54ddd9b818c23..9b04127613d22 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/build_esql_search_request.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/build_esql_search_request.ts @@ -7,6 +7,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { Filter } from '@kbn/es-query'; +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import type { RuleFilterArray, TimestampOverride, @@ -56,6 +57,7 @@ export const buildEsqlSearchRequest = ({ // we limit size of the response to maxAlertNumber + 1 // ES|QL currently does not support pagination and returns 10,000 results query: `${query} | limit ${size + 1}`, + version: ESQL_LATEST_VERSION, filter: { bool: { filter: requestFilter, diff --git a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.test.ts b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.test.ts index 1d7096d20140e..ce50dcb2edede 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.test.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.test.ts @@ -67,6 +67,7 @@ describe('fetchEsqlQuery', () => { }, }, "query": "from test", + "version": "2024.04.01", } `); }); @@ -94,6 +95,7 @@ describe('fetchEsqlQuery', () => { }, }, "query": "from test | limit 100", + "version": "2024.04.01", } `); }); diff --git a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.ts b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.ts index 87ae2c1123547..4b527f529874e 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.ts @@ -6,6 +6,7 @@ */ import { parseAggregationResults } from '@kbn/triggers-actions-ui-plugin/common'; +import { ESQL_LATEST_VERSION } from '@kbn/esql-utils'; import { SharePluginStart } from '@kbn/share-plugin/server'; import { IScopedClusterClient, Logger } from '@kbn/core/server'; import { OnlyEsqlQueryRuleParams } from '../types'; @@ -90,6 +91,7 @@ export const getEsqlQuery = ( const query = { query: alertLimit ? `${params.esqlQuery.esql} | limit ${alertLimit}` : params.esqlQuery.esql, + version: ESQL_LATEST_VERSION, filter: { bool: { filter: rangeFilter, From 15dea75d5263bae1122c38b1b24c14449c6db20d Mon Sep 17 00:00:00 2001 From: Clint Andrew Hall Date: Tue, 9 Apr 2024 12:03:35 -0400 Subject: [PATCH 25/29] [dx] Tweak profiling to include the webpack visualization from CI (#180335) --- package.json | 1 + packages/kbn-optimizer/src/worker/webpack.config.ts | 7 +++++++ yarn.lock | 9 +++++++++ 3 files changed, 17 insertions(+) diff --git a/package.json b/package.json index 816332219392a..d0f1c3a68daae 100644 --- a/package.json +++ b/package.json @@ -1519,6 +1519,7 @@ "@types/vinyl-fs": "^3.0.2", "@types/watchpack": "^1.1.5", "@types/webpack": "^4.41.3", + "@types/webpack-bundle-analyzer": "^4.7.0", "@types/webpack-env": "^1.15.3", "@types/webpack-merge": "^4.1.5", "@types/webpack-sources": "^0.1.4", diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index d36895151587f..ecf2ea603767d 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -20,6 +20,7 @@ import * as UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; import StatoscopeWebpackPlugin from '@statoscope/webpack-plugin'; // @ts-expect-error import VisualizerPlugin from 'webpack-visualizer-plugin2'; +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import { Bundle, BundleRemotes, WorkerConfig, parseDllManifest } from '../common'; import { BundleRemotesPlugin } from './bundle_remotes_plugin'; @@ -92,6 +93,12 @@ export function getWebpackConfig( saveReportTo: `${bundle.outputDir}/${bundle.id}.statoscope.html`, }), new VisualizerPlugin({ filename: `${bundle.id}.visualizer.html` }), + new BundleAnalyzerPlugin({ + analyzerMode: 'static', + reportFilename: `${bundle.id}.analyzer.html`, + openAnalyzer: false, + logLevel: 'silent', + }), ] : []), // @ts-ignore something is wrong with the StatoscopeWebpackPlugin type. diff --git a/yarn.lock b/yarn.lock index 01a86c1aa0031..02456e91ca840 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10812,6 +10812,15 @@ "@types/node" "*" chokidar "^2.1.2" +"@types/webpack-bundle-analyzer@^4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@types/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz#fe199e724ce3d38705f6f1ba4d62429b7c360541" + integrity sha512-c5i2ThslSNSG8W891BRvOd/RoCjI2zwph8maD22b1adtSns20j+0azDDMCK06DiVrzTgnwiDl5Ntmu1YRJw8Sg== + dependencies: + "@types/node" "*" + tapable "^2.2.0" + webpack "^5" + "@types/webpack-env@^1.15.3", "@types/webpack-env@^1.16.0": version "1.16.3" resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.16.3.tgz#b776327a73e561b71e7881d0cd6d34a1424db86a" From c3c9df690c13a89e0e6a1ecbe32094a98f3bd410 Mon Sep 17 00:00:00 2001 From: Dan Panzarella Date: Tue, 9 Apr 2024 12:05:02 -0400 Subject: [PATCH 26/29] [Security Solution] Disable v2 transform names (#180383) --- .../security_solution/common/endpoint/utils/package_v2.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/common/endpoint/utils/package_v2.ts b/x-pack/plugins/security_solution/common/endpoint/utils/package_v2.ts index 5717f8d601502..56b23ed956770 100644 --- a/x-pack/plugins/security_solution/common/endpoint/utils/package_v2.ts +++ b/x-pack/plugins/security_solution/common/endpoint/utils/package_v2.ts @@ -5,10 +5,10 @@ * 2.0. */ -import semverLte from 'semver/functions/lte'; +// import semverLte from 'semver/functions/lte'; // switch to "v2" logic -const MIN_ENDPOINT_PACKAGE_V2_VERSION = '8.14.0-prerelease.1'; +// const MIN_ENDPOINT_PACKAGE_V2_VERSION = '8.14.0-prerelease.1'; export function isEndpointPackageV2(version: string) { - return semverLte(MIN_ENDPOINT_PACKAGE_V2_VERSION, version); + return false; } From 3839523be92cc78bf01300ca1f3e3d25fc94611b Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 9 Apr 2024 17:13:58 +0100 Subject: [PATCH 27/29] skip flaky suite (#171653, #171654) --- .../apps/integrations/policy_details.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts index f4d587daf64f1..a2b1feaabd7cd 100644 --- a/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts +++ b/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts @@ -30,7 +30,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // FLAKY: https://github.com/elastic/kibana/issues/171653 // FLAKY: https://github.com/elastic/kibana/issues/171654 - describe('When on the Endpoint Policy Details Page', function () { + describe.skip('When on the Endpoint Policy Details Page', function () { targetTags(this, ['@ess', '@serverless']); let indexedData: IndexedHostsAndAlertsResponse; From 09228a3ed6f9c2b75596b530fecf6bd33eeb68e3 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Tue, 9 Apr 2024 09:31:05 -0700 Subject: [PATCH 28/29] [ResponseOps] Remove usage of deprecated React rendering utilities (#180098) ## Summary Partially addresses https://github.com/elastic/kibana-team/issues/805 Follows https://github.com/elastic/kibana/pull/180003 These changes come up from searching in the code and finding where certain kinds of deprecated AppEx-SharedUX modules are imported. **Reviewers: Please interact with critical paths through the UI components touched in this PR, ESPECIALLY in terms of testing dark mode and i18n.** * Started with focusing on code owned by ResponseOps. * Stack Management changes trickled into this PR because ResponseOps needs the `theme` field from `ManagementAppMountParams` * Security changes trickled into this PR, in its test code, because of the Stack Management changes. ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../management_app/management_app.tsx | 58 ++++++++----------- .../management_app/management_router.tsx | 7 ++- .../management_app_wrapper.tsx | 15 ++++- src/plugins/management/public/types.ts | 4 +- src/plugins/management/tsconfig.json | 1 + .../application/maintenance_windows.tsx | 32 +++++----- .../alerting/public/lib/test_utils.tsx | 10 ++-- x-pack/plugins/alerting/tsconfig.json | 4 +- .../cases/public/common/use_cases_toast.tsx | 12 ++-- .../public/common/use_is_dark_theme.test.tsx | 46 --------------- .../cases/public/common/use_is_dark_theme.tsx | 31 ---------- .../visualizations/actions/action_wrapper.tsx | 10 ++-- .../actions/add_to_existing_case.test.tsx | 7 ++- .../actions/add_to_existing_case.tsx | 6 +- .../visualizations/actions/mocks.ts | 23 +++----- x-pack/plugins/cases/tsconfig.json | 2 +- .../api_keys/api_keys_management_app.test.tsx | 3 +- .../role_mappings_management_app.test.tsx | 5 +- .../roles/roles_management_app.test.tsx | 3 +- .../users/users_management_app.test.tsx | 3 +- .../management/spaces_management_app.test.tsx | 3 +- .../public/connector_types/lib/test_utils.tsx | 7 +-- .../public/application/alerts_app.tsx | 29 ++++------ .../public/application/app.tsx | 41 +++++++------ .../public/application/connectors_app.tsx | 29 ++++------ .../hooks/use_bulk_edit_response.tsx | 10 ++-- .../hooks/use_bulk_operation_toast.tsx | 10 ++-- .../connectors_selection.test.tsx | 12 ++-- .../toolbar/components/inspect/modal.test.tsx | 8 ++- .../rule_details/components/rule_details.tsx | 19 ++++-- .../sections/rule_form/rule_add.tsx | 7 ++- .../sections/rule_form/rule_edit.tsx | 7 ++- .../components/rule_status_dropdown.tsx | 9 ++- .../rules_list/components/rules_list.tsx | 7 ++- .../application/sections/test_utils.tsx | 8 +-- .../triggers_actions_ui/public/plugin.ts | 4 +- .../plugins/triggers_actions_ui/tsconfig.json | 5 +- 37 files changed, 217 insertions(+), 280 deletions(-) delete mode 100644 x-pack/plugins/cases/public/common/use_is_dark_theme.test.tsx delete mode 100644 x-pack/plugins/cases/public/common/use_is_dark_theme.tsx diff --git a/src/plugins/management/public/components/management_app/management_app.tsx b/src/plugins/management/public/components/management_app/management_app.tsx index c64f8e74ff3a5..d7284c450ee4a 100644 --- a/src/plugins/management/public/components/management_app/management_app.tsx +++ b/src/plugins/management/public/components/management_app/management_app.tsx @@ -10,13 +10,13 @@ import './management_app.scss'; import React, { useState, useEffect, useCallback } from 'react'; import { BehaviorSubject } from 'rxjs'; -import { I18nProvider } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { AppMountParameters, ChromeBreadcrumb, ScopedHistory } from '@kbn/core/public'; import { CoreStart } from '@kbn/core/public'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; -import { reactRouterNavigate, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { reactRouterNavigate } from '@kbn/kibana-react-plugin/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { KibanaPageTemplate, KibanaPageTemplateProps } from '@kbn/shared-ux-page-kibana-template'; import useObservable from 'react-use/lib/useObservable'; import { AppContextProvider } from './management_context'; @@ -32,7 +32,6 @@ import { SectionsServiceStart, NavigationCardsSubject } from '../../types'; interface ManagementAppProps { appBasePath: string; history: AppMountParameters['history']; - theme$: AppMountParameters['theme$']; dependencies: ManagementAppDependencies; } @@ -45,13 +44,8 @@ export interface ManagementAppDependencies { cardsNavigationConfig$: BehaviorSubject; } -export const ManagementApp = ({ - dependencies, - history, - theme$, - appBasePath, -}: ManagementAppProps) => { - const { setBreadcrumbs, isSidebarEnabled$, cardsNavigationConfig$ } = dependencies; +export const ManagementApp = ({ dependencies, history, appBasePath }: ManagementAppProps) => { + const { coreStart, setBreadcrumbs, isSidebarEnabled$, cardsNavigationConfig$ } = dependencies; const [selectedId, setSelectedId] = useState(''); const [sections, setSections] = useState(); const isSidebarEnabled = useObservable(isSidebarEnabled$); @@ -114,30 +108,28 @@ export const ManagementApp = ({ }; return ( - - + + - - - - - + + + - - + + ); }; diff --git a/src/plugins/management/public/components/management_app/management_router.tsx b/src/plugins/management/public/components/management_app/management_router.tsx index 6c62163f2356c..3d56f097127bf 100644 --- a/src/plugins/management/public/components/management_app/management_router.tsx +++ b/src/plugins/management/public/components/management_app/management_router.tsx @@ -14,6 +14,7 @@ import { AppMountParameters, ChromeBreadcrumb, ScopedHistory, + ThemeServiceStart, } from '@kbn/core/public'; import { KibanaErrorBoundary, KibanaErrorBoundaryProvider } from '@kbn/shared-ux-error-boundary'; import { ManagementAppWrapper } from '../management_app_wrapper'; @@ -22,7 +23,7 @@ import { ManagementSection } from '../../utils'; interface ManagementRouterProps { history: AppMountParameters['history']; - theme$: AppMountParameters['theme$']; + theme: ThemeServiceStart; setBreadcrumbs: (crumbs?: ChromeBreadcrumb[], appHistory?: ScopedHistory) => void; onAppMounted: (id: string) => void; sections: ManagementSection[]; @@ -35,7 +36,7 @@ export const ManagementRouter = memo( setBreadcrumbs, onAppMounted, sections, - theme$, + theme, analytics, }: ManagementRouterProps) => { return ( @@ -55,7 +56,7 @@ export const ManagementRouter = memo( setBreadcrumbs={setBreadcrumbs} onAppMounted={onAppMounted} history={history} - theme$={theme$} + theme={theme} /> )} /> diff --git a/src/plugins/management/public/components/management_app_wrapper/management_app_wrapper.tsx b/src/plugins/management/public/components/management_app_wrapper/management_app_wrapper.tsx index 6a9a5ad4baeda..8f044c15afd72 100644 --- a/src/plugins/management/public/components/management_app_wrapper/management_app_wrapper.tsx +++ b/src/plugins/management/public/components/management_app_wrapper/management_app_wrapper.tsx @@ -8,7 +8,12 @@ import React, { createRef, Component } from 'react'; -import { ChromeBreadcrumb, AppMountParameters, ScopedHistory } from '@kbn/core/public'; +import { + ChromeBreadcrumb, + AppMountParameters, + ScopedHistory, + ThemeServiceStart, +} from '@kbn/core/public'; import classNames from 'classnames'; import { APP_WRAPPER_CLASS } from '@kbn/core/public'; import { ThrowIfError } from '@kbn/shared-ux-error-boundary'; @@ -20,7 +25,7 @@ interface ManagementSectionWrapperProps { setBreadcrumbs: (crumbs?: ChromeBreadcrumb[], history?: ScopedHistory) => void; onAppMounted: (id: string) => void; history: AppMountParameters['history']; - theme$: AppMountParameters['theme$']; + theme: ThemeServiceStart; } interface ManagementSectionWrapperState { @@ -40,15 +45,19 @@ export class ManagementAppWrapper extends Component< } componentDidMount() { - const { setBreadcrumbs, app, onAppMounted, history, theme$ } = this.props; + const { setBreadcrumbs, app, onAppMounted, history, theme } = this.props; const { mount, basePath } = app; const appHistory = history.createSubHistory(app.basePath); + // TODO: Remove this: it provides a deprecated field still needed in ManagementAppMountParams + const { theme$ } = theme; + const mountResult = mount({ basePath, setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => setBreadcrumbs(crumbs, appHistory), element: this.mountElementRef.current!, history: appHistory, + theme, theme$, }); diff --git a/src/plugins/management/public/types.ts b/src/plugins/management/public/types.ts index 264a4450e8f91..eee1b8617a49a 100644 --- a/src/plugins/management/public/types.ts +++ b/src/plugins/management/public/types.ts @@ -7,7 +7,7 @@ */ import { Observable } from 'rxjs'; -import { ScopedHistory, Capabilities } from '@kbn/core/public'; +import { ScopedHistory, Capabilities, ThemeServiceStart } from '@kbn/core/public'; import type { LocatorPublic } from '@kbn/share-plugin/common'; import { ChromeBreadcrumb, CoreTheme } from '@kbn/core/public'; import type { CardsNavigationComponentProps } from '@kbn/management-cards-navigation'; @@ -70,6 +70,8 @@ export interface ManagementAppMountParams { element: HTMLElement; // element the section should render into setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; history: ScopedHistory; + theme: ThemeServiceStart; + /** @deprecated - use `theme` **/ theme$: Observable; } diff --git a/src/plugins/management/tsconfig.json b/src/plugins/management/tsconfig.json index 116debbf72496..91e0e940c8fc6 100644 --- a/src/plugins/management/tsconfig.json +++ b/src/plugins/management/tsconfig.json @@ -27,6 +27,7 @@ "@kbn/serverless", "@kbn/shared-ux-error-boundary", "@kbn/deeplinks-management", + "@kbn/react-kibana-context-render", ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/alerting/public/application/maintenance_windows.tsx b/x-pack/plugins/alerting/public/application/maintenance_windows.tsx index bb2ba1847abac..5f4b81bb716f7 100644 --- a/x-pack/plugins/alerting/public/application/maintenance_windows.tsx +++ b/x-pack/plugins/alerting/public/application/maintenance_windows.tsx @@ -7,17 +7,18 @@ import React, { Suspense } from 'react'; import ReactDOM from 'react-dom'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { Router, Routes, Route } from '@kbn/shared-ux-router'; + +import { EuiLoadingSpinner } from '@elastic/eui'; import { CoreStart } from '@kbn/core/public'; -import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; -import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { ManagementAppMountParams } from '@kbn/management-plugin/public'; -import { EuiLoadingSpinner } from '@elastic/eui'; -import { AlertingPluginStart } from '../plugin'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; +import { Route, Router, Routes } from '@kbn/shared-ux-router'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { MAINTENANCE_WINDOW_PATHS } from '../../common'; import { useLicense } from '../hooks/use_license'; +import { AlertingPluginStart } from '../plugin'; const MaintenanceWindowsLazy: React.FC = React.lazy(() => import('../pages/maintenance_windows')); const MaintenanceWindowsCreateLazy: React.FC = React.lazy( @@ -76,14 +77,13 @@ export const renderApp = ({ mountParams: ManagementAppMountParams; kibanaVersion: string; }) => { - const { element, history, theme$ } = mountParams; - const i18nCore = core.i18n; - const isDarkMode = core.theme.getTheme().darkMode; + const { element, history } = mountParams; + const { i18n, theme } = core; const queryClient = new QueryClient(); ReactDOM.render( - + - - - - - - - + + + - , + , element ); return () => { diff --git a/x-pack/plugins/alerting/public/lib/test_utils.tsx b/x-pack/plugins/alerting/public/lib/test_utils.tsx index 6e1642bfe0d36..9c7b59a1527c4 100644 --- a/x-pack/plugins/alerting/public/lib/test_utils.tsx +++ b/x-pack/plugins/alerting/public/lib/test_utils.tsx @@ -6,14 +6,14 @@ */ import React from 'react'; -import { of, BehaviorSubject } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { I18nProvider } from '@kbn/i18n-react'; -import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { KibanaThemeProvider } from '@kbn/react-kibana-context-theme'; import { render as reactRender, RenderOptions, RenderResult } from '@testing-library/react'; import { Capabilities, CoreStart } from '@kbn/core/public'; import { coreMock } from '@kbn/core/public/mocks'; -import { euiDarkVars } from '@kbn/ui-theme'; import type { ILicense } from '@kbn/licensing-plugin/public'; import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; @@ -40,8 +40,6 @@ export const createAppMockRenderer = ({ capabilities, license, }: AppMockRendererArgs = {}): AppMockRenderer => { - const theme$ = of({ eui: euiDarkVars, darkMode: true }); - const licensingPluginMock = licensingMock.createStart(); const queryClient = new QueryClient({ @@ -83,7 +81,7 @@ export const createAppMockRenderer = ({ }; const AppWrapper: React.FC<{ children: React.ReactElement }> = React.memo(({ children }) => ( - + {children} diff --git a/x-pack/plugins/alerting/tsconfig.json b/x-pack/plugins/alerting/tsconfig.json index de830800f5aea..2158a9d7d33a8 100644 --- a/x-pack/plugins/alerting/tsconfig.json +++ b/x-pack/plugins/alerting/tsconfig.json @@ -68,7 +68,9 @@ "@kbn/core-ui-settings-server-mocks", "@kbn/core-test-helpers-kbn-server", "@kbn/core-http-router-server-internal", - "@kbn/core-execution-context-server-mocks" + "@kbn/core-execution-context-server-mocks", + "@kbn/react-kibana-context-render", + "@kbn/react-kibana-context-theme" ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/cases/public/common/use_cases_toast.tsx b/x-pack/plugins/cases/public/common/use_cases_toast.tsx index 624c46aaf5a4f..71a9e3add1ae4 100644 --- a/x-pack/plugins/cases/public/common/use_cases_toast.tsx +++ b/x-pack/plugins/cases/public/common/use_cases_toast.tsx @@ -9,7 +9,7 @@ import type { ErrorToastOptions } from '@kbn/core/public'; import { EuiButtonEmpty, EuiText, logicalCSS, useEuiTheme } from '@elastic/eui'; import React, { useMemo } from 'react'; import { css } from '@emotion/react'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { isValidOwner } from '../../common/utils/owner'; import type { CaseUI } from '../../common'; import { AttachmentType } from '../../common/types/domain'; @@ -106,7 +106,8 @@ const getErrorMessage = (error: Error | ServerError): string => { export const useCasesToast = () => { const { appId } = useApplication(); - const { getUrlForApp, navigateToUrl } = useKibana().services.application; + const { application, i18n, theme } = useKibana().services; + const { getUrlForApp, navigateToUrl } = application; const toasts = useToasts(); @@ -147,12 +148,13 @@ export const useCasesToast = () => { return toasts.addSuccess({ color: 'success', iconType: 'check', - title: toMountPoint(), + title: toMountPoint(, { i18n, theme }), text: toMountPoint( + />, + { i18n, theme } ), }); }, @@ -175,7 +177,7 @@ export const useCasesToast = () => { }); }, }), - [appId, getUrlForApp, navigateToUrl, toasts] + [i18n, theme, appId, getUrlForApp, navigateToUrl, toasts] ); }; diff --git a/x-pack/plugins/cases/public/common/use_is_dark_theme.test.tsx b/x-pack/plugins/cases/public/common/use_is_dark_theme.test.tsx deleted file mode 100644 index 460fac7c01be5..0000000000000 --- a/x-pack/plugins/cases/public/common/use_is_dark_theme.test.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 { BehaviorSubject } from 'rxjs'; -import { renderHook } from '@testing-library/react-hooks'; -import { useKibana } from './lib/kibana'; -import { useIsDarkTheme } from './use_is_dark_theme'; -import type { CoreTheme } from '@kbn/core-theme-browser'; -import type { AppMockRenderer } from './mock'; -import { createAppMockRenderer } from './mock'; - -jest.mock('./lib/kibana'); - -const useKibanaMock = useKibana as jest.Mocked; - -describe('useIsDarkTheme', () => { - let appMockRender: AppMockRenderer; - - beforeEach(() => { - appMockRender = createAppMockRenderer(); - useKibanaMock().services.theme.theme$ = new BehaviorSubject({ darkMode: true }); - }); - - it('returns true if the theme is in dark mode', async () => { - const { result } = renderHook(() => useIsDarkTheme(), { - wrapper: appMockRender.AppWrapper, - }); - - expect(result.current).toBe(true); - }); - - it('returns the default theme if the theme service is undefined', async () => { - // @ts-expect-error: service maybe undefined - useKibanaMock().services.theme = undefined; - - const { result } = renderHook(() => useIsDarkTheme(), { - wrapper: appMockRender.AppWrapper, - }); - - expect(result.current).toBe(false); - }); -}); diff --git a/x-pack/plugins/cases/public/common/use_is_dark_theme.tsx b/x-pack/plugins/cases/public/common/use_is_dark_theme.tsx deleted file mode 100644 index 4e6120d953a27..0000000000000 --- a/x-pack/plugins/cases/public/common/use_is_dark_theme.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 { useMemo } from 'react'; -import { of } from 'rxjs'; -import useObservable from 'react-use/lib/useObservable'; -import { useKibana } from './lib/kibana'; - -const themeDefault = { darkMode: false }; - -/** - * Indicates if the currently applied theme is either dark or light. - * @return {boolean} - Returns true if the currently applied theme is dark. - */ -export function useIsDarkTheme(): boolean { - const { - services: { theme }, - } = useKibana(); - - const themeObservable$ = useMemo(() => { - return theme?.theme$ ?? of(themeDefault); - }, [theme]); - - const { darkMode } = useObservable(themeObservable$, themeDefault); - - return darkMode; -} diff --git a/x-pack/plugins/cases/public/components/visualizations/actions/action_wrapper.tsx b/x-pack/plugins/cases/public/components/visualizations/actions/action_wrapper.tsx index 798ddea708193..543969c731d36 100644 --- a/x-pack/plugins/cases/public/components/visualizations/actions/action_wrapper.tsx +++ b/x-pack/plugins/cases/public/components/visualizations/actions/action_wrapper.tsx @@ -8,9 +8,8 @@ import type { PropsWithChildren } from 'react'; import React from 'react'; import { Router } from '@kbn/shared-ux-router'; -import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; -import { useIsDarkTheme } from '../../../common/use_is_dark_theme'; import { SECURITY_SOLUTION_OWNER } from '../../../../common'; import type { CasesUIActionProps } from './types'; import { KibanaContextProvider, useKibana } from '../../../common/lib/kibana'; @@ -30,8 +29,7 @@ const ActionWrapperWithContext: React.FC> = ({ caseContextProps, currentAppId, }) => { - const { application } = useKibana().services; - const isDarkTheme = useIsDarkTheme(); + const { application, i18n, theme } = useKibana().services; const owner = getCaseOwnerByAppId(currentAppId); const casePermissions = canUseCases(application.capabilities)(owner ? [owner] : undefined); @@ -39,7 +37,7 @@ const ActionWrapperWithContext: React.FC> = ({ const syncAlerts = owner === SECURITY_SOLUTION_OWNER; return ( - + > = ({ > {children} - + ); }; diff --git a/x-pack/plugins/cases/public/components/visualizations/actions/add_to_existing_case.test.tsx b/x-pack/plugins/cases/public/components/visualizations/actions/add_to_existing_case.test.tsx index 6742242b71fb2..1e1eb398c991b 100644 --- a/x-pack/plugins/cases/public/components/visualizations/actions/add_to_existing_case.test.tsx +++ b/x-pack/plugins/cases/public/components/visualizations/actions/add_to_existing_case.test.tsx @@ -14,7 +14,7 @@ import { createAddToExistingCaseLensAction } from './add_to_existing_case'; import type { ActionContext } from './types'; import { useCasesAddToExistingCaseModal } from '../../all_cases/selector_modal/use_cases_add_to_existing_case_modal'; import React from 'react'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { getMockApplications$, getMockCaseUiActionProps, @@ -44,10 +44,13 @@ jest.mock('../../../client/helpers/can_use_cases', () => { }); jest.mock('@kbn/kibana-react-plugin/public', () => ({ - toMountPoint: jest.fn(), KibanaThemeProvider: jest.fn().mockImplementation(({ children }) => <>{children}), })); +jest.mock('@kbn/react-kibana-mount', () => ({ + toMountPoint: jest.fn(), +})); + jest.mock('../../../common/lib/kibana', () => { return { useKibana: jest.fn(), diff --git a/x-pack/plugins/cases/public/components/visualizations/actions/add_to_existing_case.tsx b/x-pack/plugins/cases/public/components/visualizations/actions/add_to_existing_case.tsx index b71248353ec54..647abe8b41f2a 100644 --- a/x-pack/plugins/cases/public/components/visualizations/actions/add_to_existing_case.tsx +++ b/x-pack/plugins/cases/public/components/visualizations/actions/add_to_existing_case.tsx @@ -10,7 +10,7 @@ import type { Embeddable as LensEmbeddable } from '@kbn/lens-plugin/public'; import { createAction } from '@kbn/ui-actions-plugin/public'; import { isErrorEmbeddable } from '@kbn/embeddable-plugin/public'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import type { CaseUI } from '../../../../common'; import { isLensEmbeddable, hasInput, getLensCaseAttachment } from './utils'; @@ -59,7 +59,7 @@ export const createAddToExistingCaseLensAction = ({ history, caseContextProps, }: CasesUIActionProps) => { - const { application: applicationService, theme } = core; + const { application: applicationService, i18n, theme } = core; let currentAppId: string | undefined; @@ -124,7 +124,7 @@ export const createAddToExistingCaseLensAction = ({ onSuccess={onSuccess} /> , - { theme$: theme.theme$ } + { i18n, theme } ); mount(targetDomElement); diff --git a/x-pack/plugins/cases/public/components/visualizations/actions/mocks.ts b/x-pack/plugins/cases/public/components/visualizations/actions/mocks.ts index 7957b24b1ba48..aee3b128d554b 100644 --- a/x-pack/plugins/cases/public/components/visualizations/actions/mocks.ts +++ b/x-pack/plugins/cases/public/components/visualizations/actions/mocks.ts @@ -4,23 +4,16 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { CoreTheme, PublicAppInfo } from '@kbn/core/public'; -import { BehaviorSubject, of } from 'rxjs'; -import type { TypedLensByValueInput } from '@kbn/lens-plugin/public'; -import { createBrowserHistory } from 'history'; -import type { CasesUIActionProps } from './types'; -const mockTheme: CoreTheme = { - darkMode: false, -}; +import { createBrowserHistory } from 'history'; +import { BehaviorSubject } from 'rxjs'; -const createThemeMock = (): CoreTheme => { - return { ...mockTheme }; -}; +import type { PublicAppInfo } from '@kbn/core/public'; +import { coreMock } from '@kbn/core/public/mocks'; +import type { TypedLensByValueInput } from '@kbn/lens-plugin/public'; +import type { CasesUIActionProps } from './types'; -export const createTheme$Mock = () => { - return of(createThemeMock()); -}; +const coreStart = coreMock.createStart(); export class MockEmbeddable { public type; @@ -76,8 +69,8 @@ export const getMockApplications$ = () => export const getMockCaseUiActionProps = () => { const core = { + ...coreStart, application: { currentAppId$: getMockCurrentAppId$(), capabilities: {} }, - theme: { theme$: createTheme$Mock() }, uiSettings: { get: jest.fn().mockReturnValue(true), }, diff --git a/x-pack/plugins/cases/tsconfig.json b/x-pack/plugins/cases/tsconfig.json index 1a1f8e56543bf..e493964cc088e 100644 --- a/x-pack/plugins/cases/tsconfig.json +++ b/x-pack/plugins/cases/tsconfig.json @@ -64,7 +64,6 @@ "@kbn/ui-actions-plugin", "@kbn/core-lifecycle-browser", "@kbn/core-saved-objects-api-server-mocks", - "@kbn/core-theme-browser", "@kbn/serverless", "@kbn/core-http-server", "@kbn/alerting-plugin", @@ -73,6 +72,7 @@ "@kbn/rison", "@kbn/core-application-browser", "@kbn/react-kibana-context-render", + "@kbn/react-kibana-mount", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx index 36307494a7711..dae1ffd5709f4 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx @@ -56,7 +56,8 @@ describe('apiKeysManagementApp', () => { element, setBreadcrumbs, history, - theme$: themeServiceMock.createTheme$(), + theme: coreStartMock.theme, + theme$: themeServiceMock.createTheme$(), // needed as a deprecated field in ManagementAppMountParams }); }); diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx index 8e11a1929ca16..2f0ad8f240fa3 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx @@ -40,7 +40,7 @@ async function mountApp( const setBreadcrumbs = jest.fn(); const startServices = await coreMock.createSetup().getStartServices(); - const [{ application }] = startServices; + const [{ application, theme }] = startServices; application.capabilities = { ...application.capabilities, role_mappings: { @@ -57,7 +57,8 @@ async function mountApp( element: container, setBreadcrumbs, history: scopedHistoryMock.create({ pathname }), - theme$: themeServiceMock.createTheme$(), + theme, + theme$: themeServiceMock.createTheme$(), // needed as a deprecated field in ManagementAppMountParams }); }); diff --git a/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx b/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx index 7545c69b7a95f..d9b1478905495 100644 --- a/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx @@ -55,7 +55,8 @@ async function mountApp(basePath: string, pathname: string) { element: container, setBreadcrumbs, history: scopedHistoryMock.create({ pathname }), - theme$: themeServiceMock.createTheme$(), + theme: coreStart.theme, + theme$: themeServiceMock.createTheme$(), // needed as a deprecated field in ManagementAppMountParams }); }); diff --git a/x-pack/plugins/security/public/management/users/users_management_app.test.tsx b/x-pack/plugins/security/public/management/users/users_management_app.test.tsx index 992ec3204de21..c442daf8ed273 100644 --- a/x-pack/plugins/security/public/management/users/users_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/users/users_management_app.test.tsx @@ -38,7 +38,8 @@ describe('usersManagementApp', () => { element, setBreadcrumbs, history, - theme$: themeServiceMock.createTheme$(), + theme: coreStartMock.theme, + theme$: themeServiceMock.createTheme$(), // needed as a deprecated field in ManagementAppMountParams }); }); diff --git a/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx b/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx index 2c3f613db50a0..649b74cb14ee1 100644 --- a/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx +++ b/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx @@ -58,7 +58,8 @@ async function mountApp(basePath: string, pathname: string, spaceId?: string) { element: container, setBreadcrumbs, history: scopedHistoryMock.create({ pathname }), - theme$: themeServiceMock.createTheme$(), + theme: coreStart.theme, + theme$: themeServiceMock.createTheme$(), // needed as a deprecated field in ManagementAppMountParams }); return { unmount, container, setBreadcrumbs, docTitle: coreStart.chrome.docTitle }; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/test_utils.tsx b/x-pack/plugins/stack_connectors/public/connector_types/lib/test_utils.tsx index 59a6d3808ff81..6503cc7763469 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/test_utils.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/test_utils.tsx @@ -6,14 +6,12 @@ */ import React, { useCallback } from 'react'; -import { of } from 'rxjs'; import { I18nProvider } from '@kbn/i18n-react'; import { EuiButton } from '@elastic/eui'; import { Form, useForm, FormData } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { act } from 'react-dom/test-utils'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { render as reactRender, RenderOptions, RenderResult } from '@testing-library/react'; -import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { ConnectorServices } from '@kbn/triggers-actions-ui-plugin/public/types'; import { TriggersAndActionsUiServices } from '@kbn/triggers-actions-ui-plugin/public'; @@ -93,13 +91,10 @@ export interface AppMockRenderer { export const createAppMockRenderer = (): AppMockRenderer => { const services = createStartServicesMock(); - const theme$ = of({ darkMode: false }); const AppWrapper: React.FC<{ children: React.ReactElement }> = ({ children }) => ( - - {children} - + {children} ); AppWrapper.displayName = 'AppWrapper'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/alerts_app.tsx b/x-pack/plugins/triggers_actions_ui/public/application/alerts_app.tsx index 9bf267fb9852a..5b1ac69c0fa66 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/alerts_app.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/alerts_app.tsx @@ -8,10 +8,8 @@ import React, { lazy } from 'react'; import { Router, Routes, Route } from '@kbn/shared-ux-router'; import { render, unmountComponentAtNode } from 'react-dom'; -import { I18nProvider } from '@kbn/i18n-react'; -import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; -import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { suspendedComponentWithProps } from './lib/suspended_component_with_props'; import { setDataViewsService } from '../common/lib/data_apis'; @@ -29,23 +27,18 @@ export const renderApp = (deps: TriggersAndActionsUiServices) => { }; export const App = ({ deps }: { deps: TriggersAndActionsUiServices }) => { - const { dataViews, theme, theme$ } = deps; - const isDarkMode = theme.getTheme().darkMode; + const { dataViews, i18n, theme } = deps; setDataViewsService(dataViews); return ( - - - - - - - - - - - - - + + + + + + + + + ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/app.tsx b/x-pack/plugins/triggers_actions_ui/public/application/app.tsx index 808778e95a623..6116f4571990d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/app.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/app.tsx @@ -8,12 +8,16 @@ import React, { lazy } from 'react'; import { Redirect } from 'react-router-dom'; import { Router, Routes, Route } from '@kbn/shared-ux-router'; -import { ChromeBreadcrumb, CoreStart, CoreTheme, ScopedHistory } from '@kbn/core/public'; +import { + ChromeBreadcrumb, + CoreStart, + I18nStart, + ScopedHistory, + ThemeServiceStart, +} from '@kbn/core/public'; import { render, unmountComponentAtNode } from 'react-dom'; -import { I18nProvider } from '@kbn/i18n-react'; -import { Observable } from 'rxjs'; import { KibanaFeature } from '@kbn/features-plugin/common'; -import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { ChartsPluginStart } from '@kbn/charts-plugin/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; @@ -26,7 +30,6 @@ import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { ActionsPublicPluginSetup } from '@kbn/actions-plugin/public'; import { ruleDetailsRoute } from '@kbn/rule-data-utils'; import { QueryClientProvider } from '@tanstack/react-query'; @@ -74,7 +77,8 @@ export interface TriggersAndActionsUiServices extends CoreStart { history: ScopedHistory; kibanaFeatures: KibanaFeature[]; element: HTMLElement; - theme$: Observable; + i18n: I18nStart; + theme: ThemeServiceStart; unifiedSearch: UnifiedSearchPublicPluginStart; licensing: LicensingPluginStart; expressions: ExpressionsStart; @@ -92,26 +96,21 @@ export const renderApp = (deps: TriggersAndActionsUiServices) => { }; export const App = ({ deps }: { deps: TriggersAndActionsUiServices }) => { - const { dataViews, theme } = deps; + const { dataViews, i18n, theme } = deps; const sections: Section[] = ['rules', 'logs']; - const isDarkMode = theme.getTheme().darkMode; const sectionsRegex = sections.join('|'); setDataViewsService(dataViews); return ( - - - - - - - - - - - - - + + + + + + + + + ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/connectors_app.tsx b/x-pack/plugins/triggers_actions_ui/public/application/connectors_app.tsx index 8d23a724f2571..8fe0d9745d1c2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/connectors_app.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/connectors_app.tsx @@ -10,10 +10,9 @@ import { Redirect } from 'react-router-dom'; import { Router, Routes, Route } from '@kbn/shared-ux-router'; import { ChromeBreadcrumb, CoreStart, CoreTheme, ScopedHistory } from '@kbn/core/public'; import { render, unmountComponentAtNode } from 'react-dom'; -import { I18nProvider } from '@kbn/i18n-react'; import { Observable } from 'rxjs'; import { KibanaFeature } from '@kbn/features-plugin/common'; -import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { ChartsPluginStart } from '@kbn/charts-plugin/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; @@ -24,7 +23,6 @@ import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import { QueryClientProvider } from '@tanstack/react-query'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { ActionsPublicPluginSetup } from '@kbn/actions-plugin/public'; import { DashboardStart } from '@kbn/dashboard-plugin/public'; import { suspendedComponentWithProps } from './lib/suspended_component_with_props'; @@ -75,26 +73,21 @@ export const renderApp = (deps: TriggersAndActionsUiServices) => { }; export const App = ({ deps }: { deps: TriggersAndActionsUiServices }) => { - const { dataViews, theme } = deps; - const isDarkMode = theme.getTheme().darkMode; + const { dataViews, i18n, theme } = deps; const sections: Section[] = ['connectors', 'logs']; const sectionsRegex = sections.join('|'); setDataViewsService(dataViews); return ( - - - - - - - - - - - - - + + + + + + + + + ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_edit_response.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_edit_response.tsx index 8958cd484f1b9..b1d69c89094e9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_edit_response.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_edit_response.tsx @@ -8,7 +8,7 @@ import React, { useCallback, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { useKibana } from '../../common/lib/kibana'; import { BulkEditResponse } from '../../types'; @@ -63,6 +63,8 @@ export interface UseBulkEditResponseProps { export function useBulkEditResponse(props: UseBulkEditResponseProps) { const { onSearchPopulate } = props; const { + i18n: i18nStart, + theme, notifications: { toasts }, } = useKibana().services; @@ -122,7 +124,7 @@ export function useBulkEditResponse(props: UseBulkEditResponseProps) { if (numberOfErrors === total) { toasts.addDanger({ title: failureMessage(numberOfErrors, translationMap[property]), - text: toMountPoint(renderToastErrorBody(response)), + text: toMountPoint(renderToastErrorBody(response), { i18n: i18nStart, theme }), }); return; } @@ -130,10 +132,10 @@ export function useBulkEditResponse(props: UseBulkEditResponseProps) { // Some failure toasts.addWarning({ title: someSuccessMessage(numberOfSuccess, numberOfErrors, translationMap[property]), - text: toMountPoint(renderToastErrorBody(response)), + text: toMountPoint(renderToastErrorBody(response), { i18n: i18nStart, theme }), }); }, - [toasts, renderToastErrorBody] + [i18nStart, theme, toasts, renderToastErrorBody] ); return useMemo(() => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_operation_toast.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_operation_toast.tsx index b71b0abaec7a3..88ad5c8f52958 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_operation_toast.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_operation_toast.tsx @@ -7,7 +7,7 @@ import React, { useCallback, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import type { BulkOperationError } from '@kbn/alerting-plugin/server'; import { useKibana } from '../../common/lib/kibana'; import { @@ -48,6 +48,8 @@ export const useBulkOperationToast = ({ onSearchPopulate?: (filter: string) => void; }) => { const { + i18n, + theme, notifications: { toasts }, } = useKibana().services; @@ -120,7 +122,7 @@ export const useBulkOperationToast = ({ SINGLE_RULE_TITLE, MULTIPLE_RULE_TITLE ), - text: toMountPoint(renderToastErrorBody(errors, 'danger')), + text: toMountPoint(renderToastErrorBody(errors, 'danger'), { i18n, theme }), }); return; } @@ -133,10 +135,10 @@ export const useBulkOperationToast = ({ SINGLE_RULE_TITLE, MULTIPLE_RULE_TITLE ), - text: toMountPoint(renderToastErrorBody(errors, 'warning')), + text: toMountPoint(renderToastErrorBody(errors, 'warning'), { i18n, theme }), }); }, - [toasts, renderToastErrorBody] + [i18n, theme, toasts, renderToastErrorBody] ); return useMemo(() => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connectors_selection.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connectors_selection.test.tsx index e3bf983d7bd09..afb483b70f007 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connectors_selection.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connectors_selection.test.tsx @@ -6,15 +6,17 @@ */ import * as React from 'react'; +import { coreMock } from '@kbn/core/public/mocks'; import { render, screen } from '@testing-library/react'; import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; +import { KibanaThemeProvider } from '@kbn/react-kibana-context-theme'; import { ConnectorsSelection } from './connectors_selection'; import { actionTypeRegistryMock } from '../../action_type_registry.mock'; import { ActionType, GenericValidationResult } from '../../../types'; import { EuiFieldText } from '@elastic/eui'; describe('connectors_selection', () => { + const core = coreMock.createStart(); const mockedActionParamsFields = React.lazy(async () => ({ default() { return ( @@ -92,7 +94,7 @@ describe('connectors_selection', () => { it('renders a selector', () => { const wrapper = mountWithIntl( - + { connectors={connectors} onConnectorSelected={jest.fn()} /> - + ); expect( @@ -111,7 +113,7 @@ describe('connectors_selection', () => { it('renders the title of the connector', () => { render( - + { connectors={connectors} onConnectorSelected={jest.fn()} /> - + ); expect(screen.getByRole('combobox')).toHaveValue('test pagerduty'); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/toolbar/components/inspect/modal.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/toolbar/components/inspect/modal.test.tsx index f885610e33c6f..cb08e3f672fd8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/toolbar/components/inspect/modal.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/toolbar/components/inspect/modal.test.tsx @@ -6,8 +6,9 @@ */ import React from 'react'; +import { of } from 'rxjs'; import { fireEvent, render, screen } from '@testing-library/react'; -import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; +import { KibanaThemeProvider } from '@kbn/react-kibana-context-theme'; import type { ModalInspectProps } from './modal'; import { ModalInspectQuery } from './modal'; @@ -42,8 +43,11 @@ describe('Modal Inspect', () => { }; const renderModalInspectQuery = () => { + const theme = { theme$: of({ darkMode: false }) }; return render(, { - wrapper: ({ children }) => {children}, + wrapper: ({ children }) => ( + {children} + ), }); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.tsx index 8bb60c0706f15..7421bec047e03 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.tsx @@ -24,7 +24,7 @@ import { EuiIconTip, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { RuleExecutionStatusErrorReasons, parseDuration } from '@kbn/alerting-plugin/common'; import { getRuleDetailsRoute } from '@kbn/rule-data-utils'; import { UpdateApiKeyModalConfirmation } from '../../../components/update_api_key_modal_confirmation'; @@ -90,12 +90,9 @@ const ruleDetailStyle = { export const RuleDetails: React.FunctionComponent = ({ rule, ruleType, - actionTypes, bulkDisableRules, bulkEnableRules, bulkDeleteRules, - snoozeRule, - unsnoozeRule, requestRefresh, refreshToken, }) => { @@ -107,6 +104,8 @@ export const RuleDetails: React.FunctionComponent = ({ setBreadcrumbs, chrome, http, + i18n: i18nStart, + theme, notifications: { toasts }, } = useKibana().services; const ruleReducer = useMemo(() => getRuleReducer(actionTypeRegistry), [actionTypeRegistry]); @@ -218,12 +217,20 @@ export const RuleDetails: React.FunctionComponent = ({ )} - + , + { i18n: i18nStart, theme } ), }); } } - }, [rule.schedule.interval, config.minimumScheduleInterval, toasts, hasEditButton]); + }, [ + i18nStart, + theme, + rule.schedule.interval, + config.minimumScheduleInterval, + toasts, + hasEditButton, + ]); const setRule = async () => { history.push(getRuleDetailsRoute(rule.id)); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx index 1b12fbffa4a1b..ef8057c0144d1 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx @@ -10,7 +10,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { EuiTitle, EuiFlyoutHeader, EuiFlyout, EuiFlyoutBody, EuiPortal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { isEmpty } from 'lodash'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { parseRuleCircuitBreakerErrorMessage } from '@kbn/alerting-plugin/common'; import { Rule, @@ -125,6 +125,8 @@ const RuleAdd = < http, notifications: { toasts }, application: { capabilities }, + i18n: i18nStart, + theme, } = useKibana().services; const canShowActions = hasShowActionsCapability(capabilities); @@ -270,7 +272,8 @@ const RuleAdd = < title: message.summary, ...(message.details && { text: toMountPoint( - {message.details} + {message.details}, + { i18n: i18nStart, theme } ), }), }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx index e4fcd86eef445..bfad87299a523 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx @@ -26,7 +26,7 @@ import { } from '@elastic/eui'; import { cloneDeep, omit } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { parseRuleCircuitBreakerErrorMessage } from '@kbn/alerting-plugin/common'; import { Rule, @@ -138,6 +138,8 @@ export const RuleEdit = < const { http, notifications: { toasts }, + i18n: i18nStart, + theme, } = useKibana().services; const setRule = (value: Rule) => { @@ -223,7 +225,8 @@ export const RuleEdit = < title: message.summary, ...(message.details && { text: toMountPoint( - {message.details} + {message.details}, + { i18n: i18nStart, theme } ), }), }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_dropdown.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_dropdown.tsx index 1470fe2606107..624e6e5f276e7 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_dropdown.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_dropdown.tsx @@ -9,7 +9,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import moment from 'moment'; import { i18n } from '@kbn/i18n'; import type { RuleSnooze } from '@kbn/alerting-plugin/common'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { parseRuleCircuitBreakerErrorMessage } from '@kbn/alerting-plugin/common'; import { EuiLoadingSpinner, @@ -65,6 +65,8 @@ export const RuleStatusDropdown: React.FunctionComponent = ({ const { notifications: { toasts }, + i18n: i18nStart, + theme, } = useKibana().services; useEffect(() => { @@ -92,12 +94,13 @@ export const RuleStatusDropdown: React.FunctionComponent = ({ title: message.summary, ...(message.details && { text: toMountPoint( - {message.details} + {message.details}, + { i18n: i18nStart, theme } ), }), }); throw new Error(); - }, [enableRule, toasts]); + }, [i18nStart, theme, enableRule, toasts]); const onEnable = useCallback(async () => { setIsUpdating(true); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx index 92c2239f349a4..6fcce17f00542 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx @@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n'; import { capitalize, isEmpty, isEqual, sortBy } from 'lodash'; import { KueryNode } from '@kbn/es-query'; import { FormattedMessage } from '@kbn/i18n-react'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { parseRuleCircuitBreakerErrorMessage } from '@kbn/alerting-plugin/common'; import { RuleTypeModal } from '@kbn/alerts-ui-shared'; import React, { @@ -190,6 +190,8 @@ export const RulesList = ({ kibanaFeatures, notifications: { toasts }, ruleTypeRegistry, + i18n: i18nStart, + theme, } = kibanaServices; const canExecuteActions = hasExecuteActionsCapability(capabilities); @@ -692,7 +694,8 @@ export const RulesList = ({ toasts.addDanger({ title: parsedError.summary, text: toMountPoint( - {parsedError.details} + {parsedError.details}, + { theme, i18n: i18nStart } ), }); } else { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/test_utils.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/test_utils.tsx index bb55f89f15500..e6fab7c1e1edd 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/test_utils.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/test_utils.tsx @@ -7,11 +7,11 @@ import React from 'react'; import { QueryClient, QueryClientProvider, QueryClientProviderProps } from '@tanstack/react-query'; -import { of } from 'rxjs'; +import { coreMock } from '@kbn/core/public/mocks'; import { I18nProvider } from '@kbn/i18n-react'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { render as reactRender, RenderOptions, RenderResult } from '@testing-library/react'; -import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { KibanaThemeProvider } from '@kbn/react-kibana-context-theme'; import { TriggersAndActionsUiServices } from '../..'; import { createStartServicesMock } from '../../common/lib/kibana/kibana_react.mock'; @@ -31,7 +31,7 @@ export const createAppMockRenderer = ( queryClientContext?: QueryClientProviderProps['context'] ): AppMockRenderer => { const services = createStartServicesMock(); - const theme$ = of({ darkMode: false }); + const core = coreMock.createStart(); const queryClient = new QueryClient({ defaultOptions: { @@ -53,7 +53,7 @@ export const createAppMockRenderer = ( const AppWrapper: React.FC<{ children: React.ReactElement }> = React.memo(({ children }) => ( - + {children} diff --git a/x-pack/plugins/triggers_actions_ui/public/plugin.ts b/x-pack/plugins/triggers_actions_ui/public/plugin.ts index 174d3816792bf..fa0db949e3b50 100644 --- a/x-pack/plugins/triggers_actions_ui/public/plugin.ts +++ b/x-pack/plugins/triggers_actions_ui/public/plugin.ts @@ -313,7 +313,7 @@ export class Plugin unifiedSearch: pluginsStart.unifiedSearch, isCloud: Boolean(plugins.cloud?.isCloudEnabled), element: params.element, - theme$: params.theme$, + theme: params.theme, storage: new Storage(window.localStorage), setBreadcrumbs: params.setBreadcrumbs, history: params.history, @@ -411,7 +411,7 @@ export class Plugin unifiedSearch: pluginsStart.unifiedSearch, isCloud: Boolean(plugins.cloud?.isCloudEnabled), element: params.element, - theme$: params.theme$, + theme: params.theme, storage: new Storage(window.localStorage), setBreadcrumbs: params.setBreadcrumbs, history: params.history, diff --git a/x-pack/plugins/triggers_actions_ui/tsconfig.json b/x-pack/plugins/triggers_actions_ui/tsconfig.json index c25e1697986bd..794cfbd6071d3 100644 --- a/x-pack/plugins/triggers_actions_ui/tsconfig.json +++ b/x-pack/plugins/triggers_actions_ui/tsconfig.json @@ -61,7 +61,10 @@ "@kbn/code-editor", "@kbn/code-editor-mock", "@kbn/io-ts-utils", - "@kbn/lens-plugin" + "@kbn/lens-plugin", + "@kbn/react-kibana-context-render", + "@kbn/react-kibana-mount", + "@kbn/react-kibana-context-theme" ], "exclude": ["target/**/*"] } From 0d22468c0cb83259407554bb783f75d8a8d68470 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 9 Apr 2024 18:06:36 +0100 Subject: [PATCH 29/29] skip flaky suite (#180401) --- x-pack/test/security_solution_endpoint/apps/endpoint/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts index 6786f82a6fabe..58e1eec24b423 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts @@ -16,7 +16,8 @@ import { export default function (providerContext: FtrProviderContext) { const { loadTestFile, getService, getPageObjects } = providerContext; - describe('endpoint', function () { + // FLAKY: https://github.com/elastic/kibana/issues/180401 + describe.skip('endpoint', function () { const ingestManager = getService('ingestManager'); const log = getService('log'); const endpointTestResources = getService('endpointTestResources');