From 1f56f2102fd2108dc4469710e1a2765f918451b6 Mon Sep 17 00:00:00 2001 From: Vadim Kibana <82822460+vadimkibana@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:04:04 +0200 Subject: [PATCH 01/30] [ES|QL] Catch internal parsing errors (#196249) ## Summary Addresses this comment https://github.com/elastic/kibana/issues/191683#issuecomment-2338181503 Catches parser internal errors, and reports them the same as the regular parsing errors. --- .../src/parser/__tests__/columns.test.ts | 2 +- .../src/parser/__tests__/commands.test.ts | 2 +- .../src/parser/__tests__/from.test.ts | 2 +- .../src/parser/__tests__/function.test.ts | 2 +- .../src/parser/__tests__/inlinecast.test.ts | 2 +- .../src/parser/__tests__/literal.test.ts | 2 +- .../src/parser/__tests__/metrics.test.ts | 2 +- .../src/parser/__tests__/params.test.ts | 2 +- .../src/parser/__tests__/rename.test.ts | 2 +- .../src/parser/__tests__/sort.test.ts | 2 +- .../src/parser/__tests__/where.test.ts | 2 +- packages/kbn-esql-ast/src/parser/parser.ts | 85 +++++++++++++------ 12 files changed, 70 insertions(+), 37 deletions(-) diff --git a/packages/kbn-esql-ast/src/parser/__tests__/columns.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/columns.test.ts index e79c418eeb3cc..38e98104d41bd 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/columns.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/columns.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getAstAndSyntaxErrors as parse } from '..'; +import { parse } from '..'; describe('Column Identifier Expressions', () => { it('can parse un-quoted identifiers', () => { diff --git a/packages/kbn-esql-ast/src/parser/__tests__/commands.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/commands.test.ts index 30d44d447387e..6fb176c9624f7 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/commands.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/commands.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getAstAndSyntaxErrors as parse } from '..'; +import { parse } from '..'; describe('commands', () => { describe('correctly formatted, basic usage', () => { diff --git a/packages/kbn-esql-ast/src/parser/__tests__/from.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/from.test.ts index 101661973a692..f2f0fded57ca5 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/from.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/from.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getAstAndSyntaxErrors as parse } from '..'; +import { parse } from '..'; describe('FROM', () => { describe('correctly formatted', () => { diff --git a/packages/kbn-esql-ast/src/parser/__tests__/function.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/function.test.ts index 8ec533816a56e..9d822f78f9333 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/function.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/function.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getAstAndSyntaxErrors as parse } from '..'; +import { parse } from '..'; import { Walker } from '../../walker'; describe('function AST nodes', () => { diff --git a/packages/kbn-esql-ast/src/parser/__tests__/inlinecast.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/inlinecast.test.ts index d0650ab3f3213..889ca2a2ecf3d 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/inlinecast.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/inlinecast.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getAstAndSyntaxErrors as parse } from '..'; +import { parse } from '..'; import { ESQLFunction, ESQLInlineCast, ESQLSingleAstItem } from '../../types'; describe('Inline cast (::)', () => { diff --git a/packages/kbn-esql-ast/src/parser/__tests__/literal.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/literal.test.ts index 514d769d5c45e..7f50198c96047 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/literal.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/literal.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getAstAndSyntaxErrors as parse } from '..'; +import { parse } from '..'; import { ESQLLiteral } from '../../types'; describe('literal expression', () => { diff --git a/packages/kbn-esql-ast/src/parser/__tests__/metrics.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/metrics.test.ts index 54ddc49c5d048..d33c94e8903ac 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/metrics.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/metrics.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getAstAndSyntaxErrors as parse } from '..'; +import { parse } from '..'; describe('METRICS', () => { describe('correctly formatted', () => { diff --git a/packages/kbn-esql-ast/src/parser/__tests__/params.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/params.test.ts index 8586236eeb2f9..e4b1a892d32d9 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/params.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/params.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getAstAndSyntaxErrors as parse } from '..'; +import { parse } from '..'; import { Walker } from '../../walker'; /** diff --git a/packages/kbn-esql-ast/src/parser/__tests__/rename.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/rename.test.ts index 4acad891150b2..214e5c1d36882 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/rename.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/rename.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getAstAndSyntaxErrors as parse } from '..'; +import { parse } from '..'; describe('RENAME', () => { /** diff --git a/packages/kbn-esql-ast/src/parser/__tests__/sort.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/sort.test.ts index cfaec0a6e39e9..981eac40b68ae 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/sort.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/sort.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getAstAndSyntaxErrors as parse } from '..'; +import { parse } from '..'; describe('SORT', () => { describe('correctly formatted', () => { diff --git a/packages/kbn-esql-ast/src/parser/__tests__/where.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/where.test.ts index d507b559fd407..f3f6aeb886ec0 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/where.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/where.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getAstAndSyntaxErrors as parse } from '..'; +import { parse } from '..'; describe('WHERE', () => { describe('correctly formatted', () => { diff --git a/packages/kbn-esql-ast/src/parser/parser.ts b/packages/kbn-esql-ast/src/parser/parser.ts index ad263a49ebd00..f99e00e92d1e0 100644 --- a/packages/kbn-esql-ast/src/parser/parser.ts +++ b/packages/kbn-esql-ast/src/parser/parser.ts @@ -100,33 +100,66 @@ export interface ParseResult { } export const parse = (text: string | undefined, options: ParseOptions = {}): ParseResult => { - if (text == null) { - const commands: ESQLAstQueryExpression['commands'] = []; - return { ast: commands, root: Builder.expression.query(commands), errors: [], tokens: [] }; + try { + if (text == null) { + const commands: ESQLAstQueryExpression['commands'] = []; + return { ast: commands, root: Builder.expression.query(commands), errors: [], tokens: [] }; + } + const errorListener = new ESQLErrorListener(); + const parseListener = new ESQLAstBuilderListener(); + const { tokens, parser } = getParser( + CharStreams.fromString(text), + errorListener, + parseListener + ); + + parser[GRAMMAR_ROOT_RULE](); + + const errors = errorListener.getErrors().filter((error) => { + return !SYNTAX_ERRORS_TO_IGNORE.includes(error.message); + }); + const { ast: commands } = parseListener.getAst(); + const root = Builder.expression.query(commands, { + location: { + min: 0, + max: text.length - 1, + }, + }); + + if (options.withFormatting) { + const decorations = collectDecorations(tokens); + attachDecorations(root, tokens.tokens, decorations.lines); + } + + return { root, ast: commands, errors, tokens: tokens.tokens }; + } catch (error) { + /** + * Parsing should never fail, meaning this branch should never execute. But + * if it does fail, we want to log the error message for easier debugging. + */ + // eslint-disable-next-line no-console + console.error(error); + + const root = Builder.expression.query(); + + return { + root, + ast: root.commands, + errors: [ + { + startLineNumber: 0, + endLineNumber: 0, + startColumn: 0, + endColumn: 0, + message: + 'Parsing internal error: ' + + (!!error && typeof error === 'object' ? String(error.message) : String(error)), + severity: 'error', + }, + ], + tokens: [], + }; } - const errorListener = new ESQLErrorListener(); - const parseListener = new ESQLAstBuilderListener(); - const { tokens, parser } = getParser(CharStreams.fromString(text), errorListener, parseListener); - - parser[GRAMMAR_ROOT_RULE](); - - const errors = errorListener.getErrors().filter((error) => { - return !SYNTAX_ERRORS_TO_IGNORE.includes(error.message); - }); - const { ast: commands } = parseListener.getAst(); - const root = Builder.expression.query(commands, { - location: { - min: 0, - max: text.length - 1, - }, - }); - - if (options.withFormatting) { - const decorations = collectDecorations(tokens); - attachDecorations(root, tokens.tokens, decorations.lines); - } - - return { root, ast: commands, errors, tokens: tokens.tokens }; }; export const parseErrors = (text: string) => { From 4ab58325a93d2870ec1dbf17c6f02bfeb8dfc24e Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:04:49 +1100 Subject: [PATCH 02/30] skip failing test suite (#196526) --- .../entity_store/trial_license_complete_tier/engine.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine.ts index c10144aec0342..a7d32767f50ce 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine.ts @@ -14,7 +14,8 @@ export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const utils = EntityStoreUtils(getService); - describe('@ess @skipInServerlessMKI Entity Store Engine APIs', () => { + // Failing: See https://github.com/elastic/kibana/issues/196526 + describe.skip('@ess @skipInServerlessMKI Entity Store Engine APIs', () => { const dataView = dataViewRouteHelpersFactory(supertest); before(async () => { From 4edb91bb70f2e86bb756723549d5b90daee9f84c Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:11:16 +1100 Subject: [PATCH 03/30] skip failing test suite (#196470) --- .../trial_license_complete_tier/perform_bulk_action_ess.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/perform_bulk_action_ess.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/perform_bulk_action_ess.ts index 3e3eb594cc0bc..303425fca9b09 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/perform_bulk_action_ess.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/perform_bulk_action_ess.ts @@ -47,7 +47,8 @@ export default ({ getService }: FtrProviderContext): void => { const createWebHookConnector = () => createConnector(getWebHookAction()); // Failing: See https://github.com/elastic/kibana/issues/173804 - describe('@ess perform_bulk_action - ESS specific logic', () => { + // Failing: See https://github.com/elastic/kibana/issues/196470 + describe.skip('@ess perform_bulk_action - ESS specific logic', () => { beforeEach(async () => { await deleteAllRules(supertest, log); }); From 3e86a7c7d3d6acf5116245b939d4ae6ea8006051 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:11:56 +1100 Subject: [PATCH 04/30] skip failing test suite (#196492) --- .../saved_objects/trial_license_complete_tier/notes.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/notes.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/notes.ts index 5d1fefadb2f65..027c0a20262a8 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/notes.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/notes.ts @@ -15,7 +15,8 @@ export default function ({ getService }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const supertest = getService('supertest'); - describe('Note - Saved Objects', () => { + // Failing: See https://github.com/elastic/kibana/issues/196492 + describe.skip('Note - Saved Objects', () => { const es = getService('es'); before(() => kibanaServer.savedObjects.cleanStandardList()); From 9bca8b744af8bf2b2b5e5ff74680c494ae7d1824 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:12:22 +1100 Subject: [PATCH 05/30] skip failing test suite (#196462) --- .../trial_license_complete_tier/perform_bulk_action_ess.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/perform_bulk_action_ess.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/perform_bulk_action_ess.ts index 303425fca9b09..0fb8644f5e93c 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/perform_bulk_action_ess.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/perform_bulk_action_ess.ts @@ -48,6 +48,7 @@ export default ({ getService }: FtrProviderContext): void => { // Failing: See https://github.com/elastic/kibana/issues/173804 // Failing: See https://github.com/elastic/kibana/issues/196470 + // Failing: See https://github.com/elastic/kibana/issues/196462 describe.skip('@ess perform_bulk_action - ESS specific logic', () => { beforeEach(async () => { await deleteAllRules(supertest, log); From 501874f2a8097e056b629c1fb14b246e8d4b4102 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:12:58 +1100 Subject: [PATCH 06/30] skip failing test suite (#196120) --- .../apps/discover/group2_data_grid1/_data_grid_context.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/functional/apps/discover/group2_data_grid1/_data_grid_context.ts b/test/functional/apps/discover/group2_data_grid1/_data_grid_context.ts index 0757304199d8a..6a7a3fc80343e 100644 --- a/test/functional/apps/discover/group2_data_grid1/_data_grid_context.ts +++ b/test/functional/apps/discover/group2_data_grid1/_data_grid_context.ts @@ -40,7 +40,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); const security = getService('security'); - describe('discover data grid context tests', () => { + // Failing: See https://github.com/elastic/kibana/issues/196120 + describe.skip('discover data grid context tests', () => { before(async () => { await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); From 4ac575b3b291743af5fcd70f795ca43ad805fbe7 Mon Sep 17 00:00:00 2001 From: Katerina Date: Wed, 16 Oct 2024 15:16:05 +0300 Subject: [PATCH 07/30] [Inventory] Add Technical preview icon and link to docs (#196353) ## Summary closes https://github.com/elastic/kibana/issues/196264 https://github.com/user-attachments/assets/a8fdf896-5d55-4060-a274-d2a4188c62b2 --- .../enable_entity_model_button.tsx | 3 +++ .../inventory_page_template/no_data_config.tsx | 14 +++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entity_enablement/enable_entity_model_button.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_enablement/enable_entity_model_button.tsx index 6f13c33585bca..7941881ff2c51 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entity_enablement/enable_entity_model_button.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_enablement/enable_entity_model_button.tsx @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import React, { useState } from 'react'; import { EntityManagerUnauthorizedError } from '@kbn/entityManager-plugin/public'; import type { IHttpFetchError, ResponseErrorBody } from '@kbn/core/public'; +import { TechnicalPreviewBadge } from '@kbn/observability-shared-plugin/public'; import { useKibana } from '../../hooks/use_kibana'; import { Unauthorized } from './unauthorized_modal'; @@ -57,6 +58,8 @@ export function EnableEntityModelButton({ onSuccess }: { onSuccess: () => void } data-test-subj="inventoryInventoryPageTemplateFilledButton" fill onClick={handleEnablement} + iconType={() => } + iconSide="right" > {i18n.translate('xpack.inventory.noData.card.button', { defaultMessage: 'Enable', diff --git a/x-pack/plugins/observability_solution/inventory/public/components/inventory_page_template/no_data_config.tsx b/x-pack/plugins/observability_solution/inventory/public/components/inventory_page_template/no_data_config.tsx index 3b12e11d2ba7c..79db53f39c346 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/inventory_page_template/no_data_config.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/inventory_page_template/no_data_config.tsx @@ -33,8 +33,20 @@ export function getEntityManagerEnablement({ description: ( + {i18n.translate('xpack.inventory.noData.card.description.inventory', { + defaultMessage: 'Inventory', + })} + + ), link: ( Date: Wed, 16 Oct 2024 14:29:03 +0200 Subject: [PATCH 08/30] [Global Search] Add multiword type handling in global search (#196087) ## Summary This PR improves the UX of global search by allowing users to search for types that consist of multiple words without having to turn them into phrases (wrapping them in quotes). For example: The following query: ``` hello type:canvas workpad type:enterprise search world tag:new ``` Will get mapped to: ``` hello type:"canvas workpad" type:"enterprise search" world tag:new ``` Which will result in following `Query` object: ```json { "term": "hello world", "filters": { "tags": ["new"] "types": ["canvas workpad", "enterprise search"], }, } ``` Fixes: #176877 ### Checklist - [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 --- .../public/components/search_bar.tsx | 2 +- .../search_syntax/parse_search_params.test.ts | 86 +++++++++++++++++-- .../search_syntax/parse_search_params.ts | 48 ++++++++++- 3 files changed, 124 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/global_search_bar/public/components/search_bar.tsx b/x-pack/plugins/global_search_bar/public/components/search_bar.tsx index b1473c56b37ed..efc564089fb43 100644 --- a/x-pack/plugins/global_search_bar/public/components/search_bar.tsx +++ b/x-pack/plugins/global_search_bar/public/components/search_bar.tsx @@ -173,7 +173,7 @@ export const SearchBar: FC = (opts) => { reportEvent.searchRequest(); } - const rawParams = parseSearchParams(searchValue.toLowerCase()); + const rawParams = parseSearchParams(searchValue.toLowerCase(), searchableTypes); let tagIds: string[] | undefined; if (taggingApi && rawParams.filters.tags) { tagIds = rawParams.filters.tags.map( diff --git a/x-pack/plugins/global_search_bar/public/search_syntax/parse_search_params.test.ts b/x-pack/plugins/global_search_bar/public/search_syntax/parse_search_params.test.ts index c6df745be847f..8e24f599ce1d2 100644 --- a/x-pack/plugins/global_search_bar/public/search_syntax/parse_search_params.test.ts +++ b/x-pack/plugins/global_search_bar/public/search_syntax/parse_search_params.test.ts @@ -9,12 +9,12 @@ import { parseSearchParams } from './parse_search_params'; describe('parseSearchParams', () => { it('returns the correct term', () => { - const searchParams = parseSearchParams('tag:(my-tag OR other-tag) hello'); + const searchParams = parseSearchParams('tag:(my-tag OR other-tag) hello', []); expect(searchParams.term).toEqual('hello'); }); it('returns the raw query as `term` in case of parsing error', () => { - const searchParams = parseSearchParams('tag:((()^invalid'); + const searchParams = parseSearchParams('tag:((()^invalid', []); expect(searchParams).toEqual({ term: 'tag:((()^invalid', filters: {}, @@ -22,12 +22,12 @@ describe('parseSearchParams', () => { }); it('returns `undefined` term if query only contains field clauses', () => { - const searchParams = parseSearchParams('tag:(my-tag OR other-tag)'); + const searchParams = parseSearchParams('tag:(my-tag OR other-tag)', []); expect(searchParams.term).toBeUndefined(); }); it('returns correct filters when no field clause is defined', () => { - const searchParams = parseSearchParams('hello'); + const searchParams = parseSearchParams('hello', []); expect(searchParams.filters).toEqual({ tags: undefined, types: undefined, @@ -35,7 +35,7 @@ describe('parseSearchParams', () => { }); it('returns correct filters when field clauses are present', () => { - const searchParams = parseSearchParams('tag:foo type:bar hello tag:dolly'); + const searchParams = parseSearchParams('tag:foo type:bar hello tag:dolly', []); expect(searchParams).toEqual({ term: 'hello', filters: { @@ -46,7 +46,7 @@ describe('parseSearchParams', () => { }); it('considers unknown field clauses to be part of the raw search term', () => { - const searchParams = parseSearchParams('tag:foo unknown:bar hello'); + const searchParams = parseSearchParams('tag:foo unknown:bar hello', []); expect(searchParams).toEqual({ term: 'unknown:bar hello', filters: { @@ -56,7 +56,7 @@ describe('parseSearchParams', () => { }); it('handles aliases field clauses', () => { - const searchParams = parseSearchParams('tag:foo tags:bar type:dash types:board hello'); + const searchParams = parseSearchParams('tag:foo tags:bar type:dash types:board hello', []); expect(searchParams).toEqual({ term: 'hello', filters: { @@ -67,7 +67,7 @@ describe('parseSearchParams', () => { }); it('converts boolean and number values to string for known filters', () => { - const searchParams = parseSearchParams('tag:42 tags:true type:69 types:false hello'); + const searchParams = parseSearchParams('tag:42 tags:true type:69 types:false hello', []); expect(searchParams).toEqual({ term: 'hello', filters: { @@ -76,4 +76,74 @@ describe('parseSearchParams', () => { }, }); }); + + it('converts multiword searchable types to phrases so they get picked up as types', () => { + const mockSearchableMultiwordTypes = ['canvas-workpad', 'enterprise search']; + const searchParams = parseSearchParams( + 'type:canvas workpad types:canvas-workpad hello type:enterprise search type:not multiword', + mockSearchableMultiwordTypes + ); + expect(searchParams).toEqual({ + term: 'hello multiword', + filters: { + types: ['canvas workpad', 'enterprise search', 'not'], + }, + }); + }); + + it('parses correctly when multiword types are already quoted', () => { + const mockSearchableMultiwordTypes = ['canvas-workpad']; + const searchParams = parseSearchParams( + `type:"canvas workpad" hello type:"dashboard"`, + mockSearchableMultiwordTypes + ); + expect(searchParams).toEqual({ + term: 'hello', + filters: { + types: ['canvas workpad', 'dashboard'], + }, + }); + }); + + it('parses correctly when there is whitespace between type keyword and value', () => { + const mockSearchableMultiwordTypes = ['canvas-workpad']; + const searchParams = parseSearchParams( + 'type: canvas workpad hello type: dashboard', + mockSearchableMultiwordTypes + ); + expect(searchParams).toEqual({ + term: 'hello', + filters: { + types: ['canvas workpad', 'dashboard'], + }, + }); + }); + + it('dedupes duplicate types', () => { + const mockSearchableMultiwordTypes = ['canvas-workpad']; + const searchParams = parseSearchParams( + 'type:canvas workpad hello type:dashboard type:canvas-workpad type:canvas workpad type:dashboard', + mockSearchableMultiwordTypes + ); + expect(searchParams).toEqual({ + term: 'hello', + filters: { + types: ['canvas workpad', 'dashboard'], + }, + }); + }); + + it('handles whitespace removal even if there are no multiword types', () => { + const mockSearchableMultiwordTypes: string[] = []; + const searchParams = parseSearchParams( + 'hello type: dashboard', + mockSearchableMultiwordTypes + ); + expect(searchParams).toEqual({ + term: 'hello', + filters: { + types: ['dashboard'], + }, + }); + }); }); diff --git a/x-pack/plugins/global_search_bar/public/search_syntax/parse_search_params.ts b/x-pack/plugins/global_search_bar/public/search_syntax/parse_search_params.ts index 1df6c1123a328..90ba36cce5fcb 100644 --- a/x-pack/plugins/global_search_bar/public/search_syntax/parse_search_params.ts +++ b/x-pack/plugins/global_search_bar/public/search_syntax/parse_search_params.ts @@ -16,12 +16,54 @@ const aliasMap = { type: ['types'], }; -export const parseSearchParams = (term: string): ParsedSearchParams => { +// Converts multiword types to phrases by wrapping them in quotes and trimming whitespace after type keyword. Example: type: canvas workpad -> type:"canvas workpad". If the type is already wrapped in quotes or is a single word, it will only trim whitespace after type keyword. +const convertMultiwordTypesToPhrasesAndTrimWhitespace = ( + term: string, + multiWordTypes: string[] +): string => { + if (!multiWordTypes.length) { + return term.replace( + /(type:|types:)\s*([^"']*?)\b([^"'\s]+)/gi, + (_, typeKeyword, whitespace, typeValue) => `${typeKeyword}${whitespace.trim()}${typeValue}` + ); + } + + const typesPattern = multiWordTypes.join('|'); + const termReplaceRegex = new RegExp( + `(type:|types:)\\s*([^"']*?)\\b((${typesPattern})\\b|[^\\s"']+)`, + 'gi' + ); + + return term.replace(termReplaceRegex, (_, typeKeyword, whitespace, typeValue) => { + const trimmedTypeKeyword = `${typeKeyword}${whitespace.trim()}`; + + // If the type value is already wrapped in quotes, leave it as is + return /['"]/.test(typeValue) + ? `${trimmedTypeKeyword}${typeValue}` + : `${trimmedTypeKeyword}"${typeValue}"`; + }); +}; + +const dedupeTypes = (types: FilterValues): FilterValues => [ + ...new Set(types.map((item) => item.replace(/[-\s]+/g, ' ').trim())), +]; + +export const parseSearchParams = (term: string, searchableTypes: string[]): ParsedSearchParams => { const recognizedFields = knownFilters.concat(...Object.values(aliasMap)); let query: Query; + // Finds all multiword types that are separated by whitespace or hyphens + const multiWordSearchableTypesWhitespaceSeperated = searchableTypes + .filter((item) => /[ -]/.test(item)) + .map((item) => item.replace(/-/g, ' ')); + + const modifiedTerm = convertMultiwordTypesToPhrasesAndTrimWhitespace( + term, + multiWordSearchableTypesWhitespaceSeperated + ); + try { - query = Query.parse(term, { + query = Query.parse(modifiedTerm, { schema: { recognizedFields }, }); } catch (e) { @@ -42,7 +84,7 @@ export const parseSearchParams = (term: string): ParsedSearchParams => { term: searchTerm, filters: { tags: tags ? valuesToString(tags) : undefined, - types: types ? valuesToString(types) : undefined, + types: types ? dedupeTypes(valuesToString(types)) : undefined, }, }; }; From 8d77cd49996281e746a0a7138c7624867c047053 Mon Sep 17 00:00:00 2001 From: Jeramy Soucy Date: Wed, 16 Oct 2024 15:11:25 +0200 Subject: [PATCH 09/30] Sets explicit access for public platform security endpoints (#195099) Related issue: #189833 ## Summary This PR explicitly sets the access level for platform security HTTP API endpoints. This is to address restriction of internal endpoints in v9. For details, see https://github.com/elastic/kibana/issues/189833. Additionally, this PR sets the `excludeFromOAS` option where applicable, in order to refrain from generating documentation for endpoints which are public but should either remain undocumented, or should be documented as part of a specific topic (e.g. external authentication flow). Note: the invalidate sessions API has been changed to internal in serverless Endpoints excluded from OAS: - GET /api/security/logout - GET /api/security/v1/logout - /api/security/oidc/implicit - /api/security/v1/oidc/implicit - /internal/security/oidc/implicit.js - GET /api/security/oidc/callback - GET /api/security/v1/oidc - POST /api/security/oidc/initiate_login - POST /api/security/v1/oidc - GET /api/security/oidc/initiate_login - POST /api/security/saml/callback - /internal/security/reset_session_page.js - /security/access_agreement - /security/account - /internal/security/capture-url - /security/logged_out - /login - /logout - /security/overwritten_session - /spaces/space_selector --- .../server/routes/index.mock.ts | 4 +- .../server/routes/key_rotation.test.ts | 20 ++++++++ .../server/routes/key_rotation.ts | 2 +- .../routes/authentication/common.test.ts | 3 +- .../server/routes/authentication/common.ts | 6 ++- .../server/routes/authentication/oidc.ts | 15 ++++-- .../server/routes/authentication/saml.test.ts | 1 + .../server/routes/authentication/saml.ts | 1 + .../routes/authorization/privileges/get.ts | 1 + .../authorization/reset_session_page.ts | 2 +- .../server/routes/session_management/index.ts | 9 +--- .../routes/session_management/invalidate.ts | 13 ++++- .../routes/views/access_agreement.test.ts | 2 +- .../server/routes/views/access_agreement.ts | 2 +- .../server/routes/views/account_management.ts | 5 +- .../server/routes/views/capture_url.test.ts | 2 +- .../server/routes/views/capture_url.ts | 2 +- .../server/routes/views/logged_out.test.ts | 2 +- .../server/routes/views/logged_out.ts | 2 +- .../server/routes/views/login.test.ts | 2 +- .../security/server/routes/views/login.ts | 2 +- .../security/server/routes/views/logout.ts | 2 +- .../routes/views/overwritten_session.ts | 2 +- .../spaces/server/routes/views/index.test.ts | 2 +- .../spaces/server/routes/views/index.ts | 3 +- .../common/platform_security/sessions.ts | 50 +++++++++++++++---- 26 files changed, 112 insertions(+), 45 deletions(-) diff --git a/x-pack/plugins/encrypted_saved_objects/server/routes/index.mock.ts b/x-pack/plugins/encrypted_saved_objects/server/routes/index.mock.ts index 4d453f64b6954..4f486d3337632 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/routes/index.mock.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/routes/index.mock.ts @@ -13,11 +13,11 @@ import { ConfigSchema } from '../config'; import { encryptionKeyRotationServiceMock } from '../crypto/index.mock'; export const routeDefinitionParamsMock = { - create: (config: Record = {}) => ({ + create: (config: Record = {}, buildFlavor: BuildFlavor = 'traditional') => ({ router: httpServiceMock.createRouter(), logger: loggingSystemMock.create().get(), config: ConfigSchema.validate(config) as ConfigType, encryptionKeyRotationService: encryptionKeyRotationServiceMock.create(), - buildFlavor: 'traditional' as BuildFlavor, + buildFlavor, }), }; diff --git a/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.test.ts b/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.test.ts index 9b9dba6108ff3..f387e94e80990 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.test.ts @@ -44,6 +44,7 @@ describe('Key rotation routes', () => { it('correctly defines route.', () => { expect(routeConfig.options).toEqual({ + access: 'public', tags: ['access:rotateEncryptionKey', 'oas-tag:saved objects'], summary: `Rotate a key for encrypted saved objects`, description: `If a saved object cannot be decrypted using the primary encryption key, Kibana attempts to decrypt it using the specified decryption-only keys. In most of the cases this overhead is negligible, but if you're dealing with a large number of saved objects and experiencing performance issues, you may want to rotate the encryption key. @@ -83,6 +84,25 @@ describe('Key rotation routes', () => { ); }); + it('defines route as internal when build flavor is serverless', () => { + const routeParamsMock = routeDefinitionParamsMock.create( + { keyRotation: { decryptionOnlyKeys: ['b'.repeat(32)] } }, + 'serverless' + ); + defineKeyRotationRoutes(routeParamsMock); + const [config] = routeParamsMock.router.post.mock.calls.find( + ([{ path }]) => path === '/api/encrypted_saved_objects/_rotate_key' + )!; + + expect(config.options).toEqual({ + access: 'internal', + tags: ['access:rotateEncryptionKey', 'oas-tag:saved objects'], + summary: `Rotate a key for encrypted saved objects`, + description: `If a saved object cannot be decrypted using the primary encryption key, Kibana attempts to decrypt it using the specified decryption-only keys. In most of the cases this overhead is negligible, but if you're dealing with a large number of saved objects and experiencing performance issues, you may want to rotate the encryption key. + NOTE: Bulk key rotation can consume a considerable amount of resources and hence only user with a superuser role can trigger it.`, + }); + }); + it('returns 400 if decryption only keys are not specified.', async () => { const routeParamsMock = routeDefinitionParamsMock.create(); defineKeyRotationRoutes(routeParamsMock); diff --git a/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.ts b/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.ts index 80907497010da..272e74c3a69cb 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.ts @@ -41,7 +41,7 @@ export function defineKeyRotationRoutes({ }, options: { tags: ['access:rotateEncryptionKey', 'oas-tag:saved objects'], - access: buildFlavor === 'serverless' ? 'internal' : undefined, + access: buildFlavor === 'serverless' ? 'internal' : 'public', summary: `Rotate a key for encrypted saved objects`, description: `If a saved object cannot be decrypted using the primary encryption key, Kibana attempts to decrypt it using the specified decryption-only keys. In most of the cases this overhead is negligible, but if you're dealing with a large number of saved objects and experiencing performance issues, you may want to rotate the encryption key. NOTE: Bulk key rotation can consume a considerable amount of resources and hence only user with a superuser role can trigger it.`, diff --git a/x-pack/plugins/security/server/routes/authentication/common.test.ts b/x-pack/plugins/security/server/routes/authentication/common.test.ts index c494389eb7c13..0fd2c54a1e6ca 100644 --- a/x-pack/plugins/security/server/routes/authentication/common.test.ts +++ b/x-pack/plugins/security/server/routes/authentication/common.test.ts @@ -69,6 +69,7 @@ describe('Common authentication routes', () => { access: 'public', authRequired: false, tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], + excludeFromOAS: true, }); expect(routeConfig.validate).toEqual({ body: undefined, @@ -170,7 +171,7 @@ describe('Common authentication routes', () => { }); it('correctly defines route.', async () => { - expect(routeConfig.options).toBeUndefined(); + expect(routeConfig.options).toEqual({ access: 'internal' }); expect(routeConfig.validate).toBe(false); }); diff --git a/x-pack/plugins/security/server/routes/authentication/common.ts b/x-pack/plugins/security/server/routes/authentication/common.ts index e54d6e35f1669..b519171fd4fe6 100644 --- a/x-pack/plugins/security/server/routes/authentication/common.ts +++ b/x-pack/plugins/security/server/routes/authentication/common.ts @@ -48,6 +48,7 @@ export function defineCommonRoutes({ validate: { query: schema.object({}, { unknowns: 'allow' }) }, options: { access: 'public', + excludeFromOAS: true, authRequired: false, tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], }, @@ -89,10 +90,11 @@ export function defineCommonRoutes({ '/internal/security/me', ...(buildFlavor !== 'serverless' ? ['/api/security/v1/me'] : []), ]) { + const deprecated = path === '/api/security/v1/me'; router.get( - { path, validate: false }, + { path, validate: false, options: { access: deprecated ? 'public' : 'internal' } }, createLicensedRouteHandler(async (context, request, response) => { - if (path === '/api/security/v1/me') { + if (deprecated) { logger.warn( `The "${basePath.serverBasePath}${path}" endpoint is deprecated and will be removed in the next major version.`, { tags: ['deprecation'] } diff --git a/x-pack/plugins/security/server/routes/authentication/oidc.ts b/x-pack/plugins/security/server/routes/authentication/oidc.ts index 2c4ab9de1491b..69c3ce1700671 100644 --- a/x-pack/plugins/security/server/routes/authentication/oidc.ts +++ b/x-pack/plugins/security/server/routes/authentication/oidc.ts @@ -37,7 +37,7 @@ export function defineOIDCRoutes({ { path, validate: false, - options: { authRequired: false }, + options: { authRequired: false, excludeFromOAS: true }, }, (context, request, response) => { const serverBasePath = basePath.serverBasePath; @@ -68,7 +68,7 @@ export function defineOIDCRoutes({ { path: '/internal/security/oidc/implicit.js', validate: false, - options: { authRequired: false }, + options: { authRequired: false, excludeFromOAS: true }, }, (context, request, response) => { const serverBasePath = basePath.serverBasePath; @@ -106,7 +106,12 @@ export function defineOIDCRoutes({ { unknowns: 'allow' } ), }, - options: { authRequired: false, tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW] }, + options: { + access: 'public', + excludeFromOAS: true, + authRequired: false, + tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], + }, }, createLicensedRouteHandler(async (context, request, response) => { const serverBasePath = basePath.serverBasePath; @@ -184,6 +189,8 @@ export function defineOIDCRoutes({ ), }, options: { + access: 'public', + excludeFromOAS: true, authRequired: false, xsrfRequired: false, tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], @@ -227,6 +234,8 @@ export function defineOIDCRoutes({ ), }, options: { + access: 'public', + excludeFromOAS: true, authRequired: false, tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], }, diff --git a/x-pack/plugins/security/server/routes/authentication/saml.test.ts b/x-pack/plugins/security/server/routes/authentication/saml.test.ts index e952d98a38649..f693d20354e89 100644 --- a/x-pack/plugins/security/server/routes/authentication/saml.test.ts +++ b/x-pack/plugins/security/server/routes/authentication/saml.test.ts @@ -56,6 +56,7 @@ describe('SAML authentication routes', () => { expect(routeConfig.options).toEqual({ access: 'public', authRequired: false, + excludeFromOAS: true, xsrfRequired: false, tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], }); diff --git a/x-pack/plugins/security/server/routes/authentication/saml.ts b/x-pack/plugins/security/server/routes/authentication/saml.ts index ddc31fbc88b89..3c72fd908e6c4 100644 --- a/x-pack/plugins/security/server/routes/authentication/saml.ts +++ b/x-pack/plugins/security/server/routes/authentication/saml.ts @@ -38,6 +38,7 @@ export function defineSAMLRoutes({ }, options: { access: 'public', + excludeFromOAS: true, authRequired: false, xsrfRequired: false, tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], diff --git a/x-pack/plugins/security/server/routes/authorization/privileges/get.ts b/x-pack/plugins/security/server/routes/authorization/privileges/get.ts index 1d278aa676ac3..b7204faaa7ca4 100644 --- a/x-pack/plugins/security/server/routes/authorization/privileges/get.ts +++ b/x-pack/plugins/security/server/routes/authorization/privileges/get.ts @@ -26,6 +26,7 @@ export function defineGetPrivilegesRoutes({ router, authz }: RouteDefinitionPara ), }), }, + options: { access: 'public' }, }, createLicensedRouteHandler((context, request, response) => { const respectLicenseLevel = request.query.respectLicenseLevel !== 'false'; // if undefined resolve to true by default diff --git a/x-pack/plugins/security/server/routes/authorization/reset_session_page.ts b/x-pack/plugins/security/server/routes/authorization/reset_session_page.ts index 67254735b9a16..0af24ad8d8397 100644 --- a/x-pack/plugins/security/server/routes/authorization/reset_session_page.ts +++ b/x-pack/plugins/security/server/routes/authorization/reset_session_page.ts @@ -12,7 +12,7 @@ export function resetSessionPageRoutes({ httpResources }: RouteDefinitionParams) { path: '/internal/security/reset_session_page.js', validate: false, - options: { authRequired: false }, + options: { authRequired: false, excludeFromOAS: true }, }, (context, request, response) => { return response.renderJs({ diff --git a/x-pack/plugins/security/server/routes/session_management/index.ts b/x-pack/plugins/security/server/routes/session_management/index.ts index c095a77409975..041feea8a62fd 100644 --- a/x-pack/plugins/security/server/routes/session_management/index.ts +++ b/x-pack/plugins/security/server/routes/session_management/index.ts @@ -13,12 +13,5 @@ import type { RouteDefinitionParams } from '..'; export function defineSessionManagementRoutes(params: RouteDefinitionParams) { defineSessionInfoRoutes(params); defineSessionExtendRoutes(params); - - // The invalidate session API was introduced to address situations where the session index - // could grow rapidly - when session timeouts are disabled, or with anonymous access. - // In the serverless environment, sessions timeouts are always be enabled, and there is no - // anonymous access. This eliminates the need for an invalidate session HTTP API. - if (params.buildFlavor !== 'serverless') { - defineInvalidateSessionsRoutes(params); - } + defineInvalidateSessionsRoutes(params); } diff --git a/x-pack/plugins/security/server/routes/session_management/invalidate.ts b/x-pack/plugins/security/server/routes/session_management/invalidate.ts index c7d27b835edf2..a45d8f00c1ca4 100644 --- a/x-pack/plugins/security/server/routes/session_management/invalidate.ts +++ b/x-pack/plugins/security/server/routes/session_management/invalidate.ts @@ -12,7 +12,11 @@ import type { RouteDefinitionParams } from '..'; /** * Defines routes required for session invalidation. */ -export function defineInvalidateSessionsRoutes({ router, getSession }: RouteDefinitionParams) { +export function defineInvalidateSessionsRoutes({ + router, + getSession, + buildFlavor, +}: RouteDefinitionParams) { router.post( { path: '/api/security/session/_invalidate', @@ -34,7 +38,12 @@ export function defineInvalidateSessionsRoutes({ router, getSession }: RouteDefi }), }, options: { - access: 'public', + // The invalidate session API was introduced to address situations where the session index + // could grow rapidly - when session timeouts are disabled, or with anonymous access. + // In the serverless environment, sessions timeouts are always be enabled, and there is no + // anonymous access. However, keeping this endpoint available internally in serverless would + // be useful in situations where we need to batch-invalidate user sessions. + access: buildFlavor === 'serverless' ? 'internal' : 'public', tags: ['access:sessionManagement'], summary: `Invalidate user sessions`, }, diff --git a/x-pack/plugins/security/server/routes/views/access_agreement.test.ts b/x-pack/plugins/security/server/routes/views/access_agreement.test.ts index ef588ae1cfcfc..74eee1e129e2c 100644 --- a/x-pack/plugins/security/server/routes/views/access_agreement.test.ts +++ b/x-pack/plugins/security/server/routes/views/access_agreement.test.ts @@ -71,7 +71,7 @@ describe('Access agreement view routes', () => { }); it('correctly defines route.', () => { - expect(routeConfig.options).toBeUndefined(); + expect(routeConfig.options).toEqual({ excludeFromOAS: true }); expect(routeConfig.validate).toBe(false); }); diff --git a/x-pack/plugins/security/server/routes/views/access_agreement.ts b/x-pack/plugins/security/server/routes/views/access_agreement.ts index 3724892edd6df..823fbb0286f33 100644 --- a/x-pack/plugins/security/server/routes/views/access_agreement.ts +++ b/x-pack/plugins/security/server/routes/views/access_agreement.ts @@ -24,7 +24,7 @@ export function defineAccessAgreementRoutes({ const canHandleRequest = () => license.getFeatures().allowAccessAgreement; httpResources.register( - { path: '/security/access_agreement', validate: false }, + { path: '/security/access_agreement', validate: false, options: { excludeFromOAS: true } }, createLicensedRouteHandler(async (context, request, response) => canHandleRequest() ? response.renderCoreApp() diff --git a/x-pack/plugins/security/server/routes/views/account_management.ts b/x-pack/plugins/security/server/routes/views/account_management.ts index af49f325a25d2..4b3fbb78fed90 100644 --- a/x-pack/plugins/security/server/routes/views/account_management.ts +++ b/x-pack/plugins/security/server/routes/views/account_management.ts @@ -11,7 +11,8 @@ import type { RouteDefinitionParams } from '..'; * Defines routes required for the Account Management view. */ export function defineAccountManagementRoutes({ httpResources }: RouteDefinitionParams) { - httpResources.register({ path: '/security/account', validate: false }, (context, req, res) => - res.renderCoreApp() + httpResources.register( + { path: '/security/account', validate: false, options: { excludeFromOAS: true } }, + (context, req, res) => res.renderCoreApp() ); } diff --git a/x-pack/plugins/security/server/routes/views/capture_url.test.ts b/x-pack/plugins/security/server/routes/views/capture_url.test.ts index 1893ad6c9cb5f..4496ab341b085 100644 --- a/x-pack/plugins/security/server/routes/views/capture_url.test.ts +++ b/x-pack/plugins/security/server/routes/views/capture_url.test.ts @@ -34,7 +34,7 @@ describe('Capture URL view routes', () => { }); it('correctly defines route.', () => { - expect(routeConfig.options).toEqual({ authRequired: false }); + expect(routeConfig.options).toEqual({ authRequired: false, excludeFromOAS: true }); expect(routeConfig.validate).toEqual({ body: undefined, diff --git a/x-pack/plugins/security/server/routes/views/capture_url.ts b/x-pack/plugins/security/server/routes/views/capture_url.ts index 8eff92d78999d..394b799ca1f9d 100644 --- a/x-pack/plugins/security/server/routes/views/capture_url.ts +++ b/x-pack/plugins/security/server/routes/views/capture_url.ts @@ -19,7 +19,7 @@ export function defineCaptureURLRoutes({ httpResources }: RouteDefinitionParams) validate: { query: schema.object({ next: schema.maybe(schema.string()) }, { unknowns: 'ignore' }), }, - options: { authRequired: false }, + options: { authRequired: false, excludeFromOAS: true }, }, (context, request, response) => response.renderAnonymousCoreApp() ); diff --git a/x-pack/plugins/security/server/routes/views/logged_out.test.ts b/x-pack/plugins/security/server/routes/views/logged_out.test.ts index 850a533e3d93a..9aecb39750b1b 100644 --- a/x-pack/plugins/security/server/routes/views/logged_out.test.ts +++ b/x-pack/plugins/security/server/routes/views/logged_out.test.ts @@ -35,7 +35,7 @@ describe('LoggedOut view routes', () => { }); it('correctly defines route.', () => { - expect(routeConfig.options).toEqual({ authRequired: false }); + expect(routeConfig.options).toEqual({ authRequired: false, excludeFromOAS: true }); expect(routeConfig.validate).toBe(false); }); diff --git a/x-pack/plugins/security/server/routes/views/logged_out.ts b/x-pack/plugins/security/server/routes/views/logged_out.ts index 360c0fb2c9b7c..66581f574def8 100644 --- a/x-pack/plugins/security/server/routes/views/logged_out.ts +++ b/x-pack/plugins/security/server/routes/views/logged_out.ts @@ -20,7 +20,7 @@ export function defineLoggedOutRoutes({ { path: '/security/logged_out', validate: false, - options: { authRequired: false }, + options: { authRequired: false, excludeFromOAS: true }, }, async (context, request, response) => { // Authentication flow isn't triggered automatically for this route, so we should explicitly diff --git a/x-pack/plugins/security/server/routes/views/login.test.ts b/x-pack/plugins/security/server/routes/views/login.test.ts index b19ef41ca9098..11797e20523e9 100644 --- a/x-pack/plugins/security/server/routes/views/login.test.ts +++ b/x-pack/plugins/security/server/routes/views/login.test.ts @@ -52,7 +52,7 @@ describe('Login view routes', () => { }); it('correctly defines route.', () => { - expect(routeConfig.options).toEqual({ authRequired: 'optional' }); + expect(routeConfig.options).toEqual({ authRequired: 'optional', excludeFromOAS: true }); expect(routeConfig.validate).toEqual({ body: undefined, diff --git a/x-pack/plugins/security/server/routes/views/login.ts b/x-pack/plugins/security/server/routes/views/login.ts index 5d4468fcbba57..8cf8459d523b8 100644 --- a/x-pack/plugins/security/server/routes/views/login.ts +++ b/x-pack/plugins/security/server/routes/views/login.ts @@ -39,7 +39,7 @@ export function defineLoginRoutes({ { unknowns: 'allow' } ), }, - options: { authRequired: 'optional' }, + options: { authRequired: 'optional', excludeFromOAS: true }, }, async (context, request, response) => { // Default to true if license isn't available or it can't be resolved for some reason. diff --git a/x-pack/plugins/security/server/routes/views/logout.ts b/x-pack/plugins/security/server/routes/views/logout.ts index 3fb905ee10d37..d61f4e83083d2 100644 --- a/x-pack/plugins/security/server/routes/views/logout.ts +++ b/x-pack/plugins/security/server/routes/views/logout.ts @@ -12,7 +12,7 @@ import type { RouteDefinitionParams } from '..'; */ export function defineLogoutRoutes({ httpResources }: RouteDefinitionParams) { httpResources.register( - { path: '/logout', validate: false, options: { authRequired: false } }, + { path: '/logout', validate: false, options: { authRequired: false, excludeFromOAS: true } }, (context, request, response) => response.renderAnonymousCoreApp() ); } diff --git a/x-pack/plugins/security/server/routes/views/overwritten_session.ts b/x-pack/plugins/security/server/routes/views/overwritten_session.ts index 115f7ea0a093f..4ab57f2cc9e72 100644 --- a/x-pack/plugins/security/server/routes/views/overwritten_session.ts +++ b/x-pack/plugins/security/server/routes/views/overwritten_session.ts @@ -12,7 +12,7 @@ import type { RouteDefinitionParams } from '..'; */ export function defineOverwrittenSessionRoutes({ httpResources }: RouteDefinitionParams) { httpResources.register( - { path: '/security/overwritten_session', validate: false }, + { path: '/security/overwritten_session', validate: false, options: { excludeFromOAS: true } }, (context, req, res) => res.renderCoreApp() ); } diff --git a/x-pack/plugins/spaces/server/routes/views/index.test.ts b/x-pack/plugins/spaces/server/routes/views/index.test.ts index b87bfe86c022a..e42f2dcf42eaf 100644 --- a/x-pack/plugins/spaces/server/routes/views/index.test.ts +++ b/x-pack/plugins/spaces/server/routes/views/index.test.ts @@ -59,7 +59,7 @@ describe('Space Selector view routes', () => { }); it('correctly defines route.', () => { - expect(routeConfig.options).toBeUndefined(); + expect(routeConfig.options).toEqual({ excludeFromOAS: true }); expect(routeConfig.validate).toBe(false); }); diff --git a/x-pack/plugins/spaces/server/routes/views/index.ts b/x-pack/plugins/spaces/server/routes/views/index.ts index ab06b17374f13..f21a665e35525 100644 --- a/x-pack/plugins/spaces/server/routes/views/index.ts +++ b/x-pack/plugins/spaces/server/routes/views/index.ts @@ -20,7 +20,7 @@ export interface ViewRouteDeps { export function initSpacesViewsRoutes(deps: ViewRouteDeps) { deps.httpResources.register( - { path: '/spaces/space_selector', validate: false }, + { path: '/spaces/space_selector', validate: false, options: { excludeFromOAS: true } }, (context, request, response) => response.renderCoreApp() ); @@ -32,6 +32,7 @@ export function initSpacesViewsRoutes(deps: ViewRouteDeps) { schema.object({ next: schema.maybe(schema.string()) }, { unknowns: 'ignore' }) ), }, + options: { excludeFromOAS: true }, }, async (context, request, response) => { try { diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/sessions.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/sessions.ts index c76ccb81f8ce2..c102f502f9489 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/sessions.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/sessions.ts @@ -10,7 +10,6 @@ import { SupertestWithRoleScopeType } from '@kbn/test-suites-xpack/api_integrati import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { - const svlCommonApi = getService('svlCommonApi'); const samlAuth = getService('samlAuth'); const roleScopedSupertest = getService('roleScopedSupertest'); let supertestViewerWithCookieCredentials: SupertestWithRoleScopeType; @@ -26,16 +25,6 @@ export default function ({ getService }: FtrProviderContext) { }); describe('route access', () => { - describe('disabled', () => { - it('invalidate', async () => { - const { body, status } = await supertestViewerWithCookieCredentials - .post('/api/security/session/_invalidate') - .set(samlAuth.getInternalRequestHeader()) - .send({ match: 'all' }); - svlCommonApi.assertApiNotFound(body, status); - }); - }); - describe('internal', () => { it('get session info', async () => { let body: any; @@ -84,6 +73,45 @@ export default function ({ getService }: FtrProviderContext) { // expect redirect expect(status).toBe(302); }); + + it('invalidate', async () => { + const supertestAdmin = await roleScopedSupertest.getSupertestWithRoleScope('admin', { + useCookieHeader: true, + }); + + let body: any; + let status: number; + + ({ body, status } = await supertestViewerWithCookieCredentials + .post('/api/security/session/_invalidate') + .set(samlAuth.getCommonRequestHeader())); + // expect a rejection because we're not using the internal header + expect(body).toEqual({ + statusCode: 400, + error: 'Bad Request', + message: expect.stringContaining( + 'method [post] exists but is not available with the current configuration' + ), + }); + expect(status).toBe(400); + + ({ body, status } = await supertestViewerWithCookieCredentials + .post('/api/security/session/_invalidate') + .set(samlAuth.getInternalRequestHeader())); + // expect forbidden because the viewer does not have privilege to invalidate a session + expect(status).toBe(403); + + ({ body, status } = await supertestAdmin + .post('/api/security/session/_invalidate') + .set(samlAuth.getInternalRequestHeader())); + // expect 400 due to no body, admin has privilege, but the request body is missing + expect(status).toBe(400); + expect(body).toEqual({ + error: 'Bad Request', + message: '[request body]: expected a plain object value, but found [null] instead.', + statusCode: 400, + }); + }); }); }); }); From dd0af8d2852d750f463dc2cbeb8dda9d75c95363 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:42:34 +1100 Subject: [PATCH 10/30] skip failing test suite (#196546) --- .../trial_license_complete_tier/engine_nondefault_spaces.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine_nondefault_spaces.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine_nondefault_spaces.ts index de949730d3d10..481f7aa4056f6 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine_nondefault_spaces.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/engine_nondefault_spaces.ts @@ -18,7 +18,8 @@ export default ({ getService }: FtrProviderContextWithSpaces) => { const supertest = getService('supertest'); const utils = EntityStoreUtils(getService, namespace); - describe('@ess Entity Store Engine APIs in non-default space', () => { + // Failing: See https://github.com/elastic/kibana/issues/196546 + describe.skip('@ess Entity Store Engine APIs in non-default space', () => { const dataView = dataViewRouteHelpersFactory(supertest, namespace); before(async () => { From e6569f0b2503968c4b8eadd9227dca96d69fd4e9 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:43:08 +1100 Subject: [PATCH 11/30] skip failing test suite (#194305) --- .../functional/test_suites/common/discover/esql/_esql_view.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/esql/_esql_view.ts b/x-pack/test_serverless/functional/test_suites/common/discover/esql/_esql_view.ts index 1bedd0acd0cc4..89edce106f64e 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/esql/_esql_view.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/esql/_esql_view.ts @@ -35,7 +35,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { defaultIndex: 'logstash-*', }; - describe('discover esql view', function () { + // Failing: See https://github.com/elastic/kibana/issues/194305 + describe.skip('discover esql view', function () { // see details: https://github.com/elastic/kibana/issues/188816 this.tags(['failsOnMKI']); From 661458f9e9196b3618db30a68bbd6785606f1b59 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 17 Oct 2024 01:17:59 +1100 Subject: [PATCH 12/30] skip failing test suite (#196319) --- .../trial_license_complete_tier/init_and_status_apis.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/init_and_status_apis.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/init_and_status_apis.ts index 3224caa24d5e2..dd1fe34cd050a 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/init_and_status_apis.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/init_and_status_apis.ts @@ -30,7 +30,8 @@ export default ({ getService }: FtrProviderContext) => { const riskEngineRoutes = riskEngineRouteHelpersFactory(supertest); const log = getService('log'); - describe('@ess @serverless @serverlessQA init_and_status_apis', () => { + // Failing: See https://github.com/elastic/kibana/issues/196319 + describe.skip('@ess @serverless @serverlessQA init_and_status_apis', () => { before(async () => { await riskEngineRoutes.cleanUp(); }); From 50cf1b322e59419b54e19351c217c0b77af3aa0a Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 17 Oct 2024 01:20:48 +1100 Subject: [PATCH 13/30] skip failing test suite (#196153) --- .../apps/triggers_actions_ui/alert_create_flyout.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts index 3c39bd235bf97..121bb753e434b 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts @@ -94,7 +94,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await rules.common.cancelRuleCreation(); } - describe('create alert', function () { + // Failing: See https://github.com/elastic/kibana/issues/196153 + describe.skip('create alert', function () { let apmSynthtraceEsClient: ApmSynthtraceEsClient; before(async () => { await esArchiver.load( From 241a05aa68cbaa737f5ccd92c1e6f91252a3cc9b Mon Sep 17 00:00:00 2001 From: Alexi Doak <109488926+doakalexi@users.noreply.github.com> Date: Wed, 16 Oct 2024 07:25:41 -0700 Subject: [PATCH 14/30] [ResponseOps] Prepare the connector `execute` HTTP API for versioning (#194481) Towards https://github.com/elastic/response-ops-team/issues/125 ## Summary Preparing the `POST ${BASE_ACTION_API_PATH}/connector/{id}/_execute` HTTP API for versioning --------- Co-authored-by: Ying Mao --- .../routes/connector/apis/execute/index.ts | 21 +++++ .../connector/apis/execute/schemas/latest.ts | 8 ++ .../connector/apis/execute/schemas/v1.ts | 20 +++++ .../connector/apis/execute/types/latest.ts | 8 ++ .../routes/connector/apis/execute/types/v1.ts | 12 +++ .../common/routes/connector/response/index.ts | 9 +- .../connector/response/schemas/latest.ts | 1 + .../routes/connector/response/schemas/v1.ts | 52 +++++++++++ .../routes/connector/response/types/v1.ts | 12 +++ .../server/actions_client/actions_client.ts | 87 +++---------------- .../connector/methods/execute/execute.ts | 73 ++++++++++++++++ .../connector/methods/execute/index.ts | 8 ++ .../connector/methods/execute/types/index.ts | 8 ++ .../connector/methods/execute/types/types.ts | 10 +++ .../get_system_action_kibana_privileges.ts | 28 ++++++ .../actions/server/lib/is_preconfigured.ts | 14 +++ .../actions/server/lib/is_system_action.ts | 14 +++ .../{ => connector/execute}/execute.test.ts | 30 +++---- .../routes/{ => connector/execute}/execute.ts | 52 ++++------- .../server/routes/connector/execute/index.ts | 8 ++ .../connector/execute/transforms/index.ts | 10 +++ .../transform_connector_response/latest.ts | 8 ++ .../transform_connector_response/v1.ts | 21 +++++ x-pack/plugins/actions/server/routes/index.ts | 4 +- .../actions/connector_types/cases_webhook.ts | 8 +- .../tests/actions/connector_types/jira.ts | 8 +- .../tests/actions/connector_types/opsgenie.ts | 8 +- .../actions/connector_types/resilient.ts | 8 +- .../connector_types/servicenow_itom.ts | 8 +- .../connector_types/servicenow_itsm.ts | 8 +- .../actions/connector_types/servicenow_sir.ts | 8 +- .../tests/actions/connector_types/swimlane.ts | 8 +- .../tests/actions/connector_types/tines.ts | 8 +- 33 files changed, 426 insertions(+), 164 deletions(-) create mode 100644 x-pack/plugins/actions/common/routes/connector/apis/execute/index.ts create mode 100644 x-pack/plugins/actions/common/routes/connector/apis/execute/schemas/latest.ts create mode 100644 x-pack/plugins/actions/common/routes/connector/apis/execute/schemas/v1.ts create mode 100644 x-pack/plugins/actions/common/routes/connector/apis/execute/types/latest.ts create mode 100644 x-pack/plugins/actions/common/routes/connector/apis/execute/types/v1.ts create mode 100644 x-pack/plugins/actions/server/application/connector/methods/execute/execute.ts create mode 100644 x-pack/plugins/actions/server/application/connector/methods/execute/index.ts create mode 100644 x-pack/plugins/actions/server/application/connector/methods/execute/types/index.ts create mode 100644 x-pack/plugins/actions/server/application/connector/methods/execute/types/types.ts create mode 100644 x-pack/plugins/actions/server/lib/get_system_action_kibana_privileges.ts create mode 100644 x-pack/plugins/actions/server/lib/is_preconfigured.ts create mode 100644 x-pack/plugins/actions/server/lib/is_system_action.ts rename x-pack/plugins/actions/server/routes/{ => connector/execute}/execute.test.ts (85%) rename x-pack/plugins/actions/server/routes/{ => connector/execute}/execute.ts (61%) create mode 100644 x-pack/plugins/actions/server/routes/connector/execute/index.ts create mode 100644 x-pack/plugins/actions/server/routes/connector/execute/transforms/index.ts create mode 100644 x-pack/plugins/actions/server/routes/connector/execute/transforms/transform_connector_response/latest.ts create mode 100644 x-pack/plugins/actions/server/routes/connector/execute/transforms/transform_connector_response/v1.ts diff --git a/x-pack/plugins/actions/common/routes/connector/apis/execute/index.ts b/x-pack/plugins/actions/common/routes/connector/apis/execute/index.ts new file mode 100644 index 0000000000000..448428839336d --- /dev/null +++ b/x-pack/plugins/actions/common/routes/connector/apis/execute/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { + executeConnectorRequestParamsSchema, + executeConnectorRequestBodySchema, +} from './schemas/latest'; +export type { ExecuteConnectorRequestParams, ExecuteConnectorRequestBody } from './types/latest'; + +export { + executeConnectorRequestParamsSchema as executeConnectorRequestParamsSchemaV1, + executeConnectorRequestBodySchema as executeConnectorRequestBodySchemaV1, +} from './schemas/v1'; +export type { + ExecuteConnectorRequestParams as ExecuteConnectorRequestParamsV1, + ExecuteConnectorRequestBody as ExecuteConnectorRequestBodyV1, +} from './types/v1'; diff --git a/x-pack/plugins/actions/common/routes/connector/apis/execute/schemas/latest.ts b/x-pack/plugins/actions/common/routes/connector/apis/execute/schemas/latest.ts new file mode 100644 index 0000000000000..25300c97a6d2e --- /dev/null +++ b/x-pack/plugins/actions/common/routes/connector/apis/execute/schemas/latest.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 * from './v1'; diff --git a/x-pack/plugins/actions/common/routes/connector/apis/execute/schemas/v1.ts b/x-pack/plugins/actions/common/routes/connector/apis/execute/schemas/v1.ts new file mode 100644 index 0000000000000..1f41763a004a2 --- /dev/null +++ b/x-pack/plugins/actions/common/routes/connector/apis/execute/schemas/v1.ts @@ -0,0 +1,20 @@ +/* + * 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 { schema } from '@kbn/config-schema'; + +export const executeConnectorRequestParamsSchema = schema.object({ + id: schema.string({ + meta: { + description: 'An identifier for the connector.', + }, + }), +}); + +export const executeConnectorRequestBodySchema = schema.object({ + params: schema.recordOf(schema.string(), schema.any()), +}); diff --git a/x-pack/plugins/actions/common/routes/connector/apis/execute/types/latest.ts b/x-pack/plugins/actions/common/routes/connector/apis/execute/types/latest.ts new file mode 100644 index 0000000000000..25300c97a6d2e --- /dev/null +++ b/x-pack/plugins/actions/common/routes/connector/apis/execute/types/latest.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 * from './v1'; diff --git a/x-pack/plugins/actions/common/routes/connector/apis/execute/types/v1.ts b/x-pack/plugins/actions/common/routes/connector/apis/execute/types/v1.ts new file mode 100644 index 0000000000000..cc1b6e4cdc196 --- /dev/null +++ b/x-pack/plugins/actions/common/routes/connector/apis/execute/types/v1.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. + */ + +import type { TypeOf } from '@kbn/config-schema'; +import { executeConnectorRequestParamsSchemaV1, executeConnectorRequestBodySchemaV1 } from '..'; + +export type ExecuteConnectorRequestParams = TypeOf; +export type ExecuteConnectorRequestBody = TypeOf; diff --git a/x-pack/plugins/actions/common/routes/connector/response/index.ts b/x-pack/plugins/actions/common/routes/connector/response/index.ts index c870698329052..3a58325a542ed 100644 --- a/x-pack/plugins/actions/common/routes/connector/response/index.ts +++ b/x-pack/plugins/actions/common/routes/connector/response/index.ts @@ -6,11 +6,16 @@ */ // Latest -export type { ConnectorResponse, AllConnectorsResponse } from './types/latest'; +export type { + ConnectorResponse, + AllConnectorsResponse, + ConnectorExecuteResponse, +} from './types/latest'; export { connectorResponseSchema, allConnectorsResponseSchema, connectorTypesResponseSchema, + connectorExecuteResponseSchema, } from './schemas/latest'; // v1 @@ -18,9 +23,11 @@ export type { ConnectorResponse as ConnectorResponseV1, AllConnectorsResponse as AllConnectorsResponseV1, ConnectorTypesResponse as ConnectorTypesResponseV1, + ConnectorExecuteResponse as ConnectorExecuteResponseV1, } from './types/v1'; export { connectorResponseSchema as connectorResponseSchemaV1, allConnectorsResponseSchema as connectorWithExtraFindDataSchemaV1, connectorTypesResponseSchema as connectorTypesResponseSchemaV1, + connectorExecuteResponseSchema as connectorExecuteResponseSchemaV1, } from './schemas/v1'; diff --git a/x-pack/plugins/actions/common/routes/connector/response/schemas/latest.ts b/x-pack/plugins/actions/common/routes/connector/response/schemas/latest.ts index bc4edc5be46d0..c89efd04bc485 100644 --- a/x-pack/plugins/actions/common/routes/connector/response/schemas/latest.ts +++ b/x-pack/plugins/actions/common/routes/connector/response/schemas/latest.ts @@ -8,3 +8,4 @@ export { connectorResponseSchema } from './v1'; export { allConnectorsResponseSchema } from './v1'; export { connectorTypesResponseSchema } from './v1'; +export { connectorExecuteResponseSchema } from './v1'; diff --git a/x-pack/plugins/actions/common/routes/connector/response/schemas/v1.ts b/x-pack/plugins/actions/common/routes/connector/response/schemas/v1.ts index 5c9b95ca8fc7b..096e2f2943d80 100644 --- a/x-pack/plugins/actions/common/routes/connector/response/schemas/v1.ts +++ b/x-pack/plugins/actions/common/routes/connector/response/schemas/v1.ts @@ -98,3 +98,55 @@ export const connectorTypesResponseSchema = schema.object({ meta: { description: 'Indicates whether the action is a system action.' }, }), }); + +export const connectorExecuteResponseSchema = schema.object({ + connector_id: schema.string({ + meta: { + description: 'The identifier for the connector.', + }, + }), + status: schema.oneOf([schema.literal('ok'), schema.literal('error')], { + meta: { + description: 'The outcome of the connector execution.', + }, + }), + message: schema.maybe( + schema.string({ + meta: { + description: 'The connector execution error message.', + }, + }) + ), + service_message: schema.maybe( + schema.string({ + meta: { + description: 'An error message that contains additional details.', + }, + }) + ), + data: schema.maybe( + schema.any({ + meta: { + description: 'The connector execution data.', + }, + }) + ), + retry: schema.maybe( + schema.nullable( + schema.oneOf([schema.boolean(), schema.string()], { + meta: { + description: + 'When the status is error, identifies whether the connector execution will retry .', + }, + }) + ) + ), + errorSource: schema.maybe( + schema.oneOf([schema.literal('user'), schema.literal('framework')], { + meta: { + description: + 'When the status is error, identifies whether the error is a framework error or a user error.', + }, + }) + ), +}); diff --git a/x-pack/plugins/actions/common/routes/connector/response/types/v1.ts b/x-pack/plugins/actions/common/routes/connector/response/types/v1.ts index 3bf7401d2d0e0..499cc2ec21d48 100644 --- a/x-pack/plugins/actions/common/routes/connector/response/types/v1.ts +++ b/x-pack/plugins/actions/common/routes/connector/response/types/v1.ts @@ -10,6 +10,7 @@ import { connectorResponseSchemaV1, connectorTypesResponseSchemaV1, allConnectorsResponseSchema, + connectorExecuteResponseSchema, } from '..'; type ConnectorResponseSchemaType = TypeOf; @@ -41,3 +42,14 @@ export interface ConnectorTypesResponse { supported_feature_ids: ConnectorTypesResponseSchemaType['supported_feature_ids']; is_system_action_type: ConnectorTypesResponseSchemaType['is_system_action_type']; } + +type ConnectorExecuteResponseSchemaType = TypeOf; +export interface ConnectorExecuteResponse { + connector_id: ConnectorExecuteResponseSchemaType['connector_id']; + status: ConnectorExecuteResponseSchemaType['status']; + message?: ConnectorExecuteResponseSchemaType['message']; + service_message?: ConnectorExecuteResponseSchemaType['service_message']; + data?: ConnectorExecuteResponseSchemaType['data']; + retry?: ConnectorExecuteResponseSchemaType['retry']; + errorSource?: ConnectorExecuteResponseSchemaType['errorSource']; +} diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.ts b/x-pack/plugins/actions/server/actions_client/actions_client.ts index f485d82b2f120..edad072acbca6 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { v4 as uuidv4 } from 'uuid'; import Boom from '@hapi/boom'; import url from 'url'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; @@ -30,6 +29,7 @@ import { get } from '../application/connector/methods/get'; import { getAll, getAllSystemConnectors } from '../application/connector/methods/get_all'; import { update } from '../application/connector/methods/update'; import { listTypes } from '../application/connector/methods/list_types'; +import { execute } from '../application/connector/methods/execute'; import { GetGlobalExecutionKPIParams, GetGlobalExecutionLogParams, @@ -54,7 +54,6 @@ import { HookServices, } from '../types'; import { PreconfiguredActionDisabledModificationError } from '../lib/errors/preconfigured_action_disabled_modification'; -import { ExecuteOptions } from '../lib/action_executor'; import { ExecutionEnqueuer, ExecuteOptions as EnqueueExecutionOptions, @@ -96,6 +95,9 @@ import { connectorFromSavedObject, isConnectorDeprecated } from '../application/ import { ListTypesParams } from '../application/connector/methods/list_types/types'; import { ConnectorUpdateParams } from '../application/connector/methods/update/types'; import { ConnectorUpdate } from '../application/connector/methods/update/types/types'; +import { isPreconfigured } from '../lib/is_preconfigured'; +import { isSystemAction } from '../lib/is_system_action'; +import { ConnectorExecuteParams } from '../application/connector/methods/execute/types'; interface Action extends ConnectorUpdate { actionTypeId: string; @@ -649,75 +651,10 @@ export class ActionsClient { return result; } - private getSystemActionKibanaPrivileges(connectorId: string, params?: ExecuteOptions['params']) { - const inMemoryConnector = this.context.inMemoryConnectors.find( - (connector) => connector.id === connectorId - ); - - const additionalPrivileges = inMemoryConnector?.isSystemAction - ? this.context.actionTypeRegistry.getSystemActionKibanaPrivileges( - inMemoryConnector.actionTypeId, - params - ) - : []; - - return additionalPrivileges; - } - - public async execute({ - actionId, - params, - source, - relatedSavedObjects, - }: Omit): Promise< - ActionTypeExecutorResult - > { - const log = this.context.logger; - - if ( - (await getAuthorizationModeBySource(this.context.unsecuredSavedObjectsClient, source)) === - AuthorizationMode.RBAC - ) { - const additionalPrivileges = this.getSystemActionKibanaPrivileges(actionId, params); - let actionTypeId: string | undefined; - - try { - if (this.isPreconfigured(actionId) || this.isSystemAction(actionId)) { - const connector = this.context.inMemoryConnectors.find( - (inMemoryConnector) => inMemoryConnector.id === actionId - ); - - actionTypeId = connector?.actionTypeId; - } else { - // TODO: Optimize so we don't do another get on top of getAuthorizationModeBySource and within the actionExecutor.execute - const { attributes } = await this.context.unsecuredSavedObjectsClient.get( - 'action', - actionId - ); - - actionTypeId = attributes.actionTypeId; - } - } catch (err) { - log.debug(`Failed to retrieve actionTypeId for action [${actionId}]`, err); - } - - await this.context.authorization.ensureAuthorized({ - operation: 'execute', - additionalPrivileges, - actionTypeId, - }); - } else { - trackLegacyRBACExemption('execute', this.context.usageCounter); - } - - return this.context.actionExecutor.execute({ - actionId, - params, - source, - request: this.context.request, - relatedSavedObjects, - actionExecutionId: uuidv4(), - }); + public async execute( + connectorExecuteParams: ConnectorExecuteParams + ): Promise> { + return execute(this.context, connectorExecuteParams); } public async bulkEnqueueExecution( @@ -789,15 +726,11 @@ export class ActionsClient { } public isPreconfigured(connectorId: string): boolean { - return !!this.context.inMemoryConnectors.find( - (connector) => connector.isPreconfigured && connector.id === connectorId - ); + return isPreconfigured(this.context, connectorId); } public isSystemAction(connectorId: string): boolean { - return !!this.context.inMemoryConnectors.find( - (connector) => connector.isSystemAction && connector.id === connectorId - ); + return isSystemAction(this.context, connectorId); } public async getGlobalExecutionLogWithAuth({ diff --git a/x-pack/plugins/actions/server/application/connector/methods/execute/execute.ts b/x-pack/plugins/actions/server/application/connector/methods/execute/execute.ts new file mode 100644 index 0000000000000..f9922e0b61a8d --- /dev/null +++ b/x-pack/plugins/actions/server/application/connector/methods/execute/execute.ts @@ -0,0 +1,73 @@ +/* + * 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 { v4 as uuidv4 } from 'uuid'; +import { RawAction, ActionTypeExecutorResult } from '../../../../types'; +import { getSystemActionKibanaPrivileges } from '../../../../lib/get_system_action_kibana_privileges'; +import { isPreconfigured } from '../../../../lib/is_preconfigured'; +import { isSystemAction } from '../../../../lib/is_system_action'; +import { + getAuthorizationModeBySource, + AuthorizationMode, +} from '../../../../authorization/get_authorization_mode_by_source'; +import { trackLegacyRBACExemption } from '../../../../lib/track_legacy_rbac_exemption'; +import { ConnectorExecuteParams } from './types'; +import { ACTION_SAVED_OBJECT_TYPE } from '../../../../constants/saved_objects'; +import { ActionsClientContext } from '../../../../actions_client'; + +export async function execute( + context: ActionsClientContext, + connectorExecuteParams: ConnectorExecuteParams +): Promise> { + const log = context.logger; + const { actionId, params, source, relatedSavedObjects } = connectorExecuteParams; + + if ( + (await getAuthorizationModeBySource(context.unsecuredSavedObjectsClient, source)) === + AuthorizationMode.RBAC + ) { + const additionalPrivileges = getSystemActionKibanaPrivileges(context, actionId, params); + let actionTypeId: string | undefined; + + try { + if (isPreconfigured(context, actionId) || isSystemAction(context, actionId)) { + const connector = context.inMemoryConnectors.find( + (inMemoryConnector) => inMemoryConnector.id === actionId + ); + + actionTypeId = connector?.actionTypeId; + } else { + // TODO: Optimize so we don't do another get on top of getAuthorizationModeBySource and within the actionExecutor.execute + const { attributes } = await context.unsecuredSavedObjectsClient.get( + ACTION_SAVED_OBJECT_TYPE, + actionId + ); + + actionTypeId = attributes.actionTypeId; + } + } catch (err) { + log.debug(`Failed to retrieve actionTypeId for action [${actionId}]`, err); + } + + await context.authorization.ensureAuthorized({ + operation: 'execute', + additionalPrivileges, + actionTypeId, + }); + } else { + trackLegacyRBACExemption('execute', context.usageCounter); + } + + return context.actionExecutor.execute({ + actionId, + params, + source, + request: context.request, + relatedSavedObjects, + actionExecutionId: uuidv4(), + }); +} diff --git a/x-pack/plugins/actions/server/application/connector/methods/execute/index.ts b/x-pack/plugins/actions/server/application/connector/methods/execute/index.ts new file mode 100644 index 0000000000000..21598e68a047c --- /dev/null +++ b/x-pack/plugins/actions/server/application/connector/methods/execute/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 { execute } from './execute'; diff --git a/x-pack/plugins/actions/server/application/connector/methods/execute/types/index.ts b/x-pack/plugins/actions/server/application/connector/methods/execute/types/index.ts new file mode 100644 index 0000000000000..ff2bc6be97a80 --- /dev/null +++ b/x-pack/plugins/actions/server/application/connector/methods/execute/types/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 type { ConnectorExecuteParams } from './types'; diff --git a/x-pack/plugins/actions/server/application/connector/methods/execute/types/types.ts b/x-pack/plugins/actions/server/application/connector/methods/execute/types/types.ts new file mode 100644 index 0000000000000..22aa019de599f --- /dev/null +++ b/x-pack/plugins/actions/server/application/connector/methods/execute/types/types.ts @@ -0,0 +1,10 @@ +/* + * 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 { ExecuteOptions } from '../../../../../lib/action_executor'; + +export type ConnectorExecuteParams = Omit; diff --git a/x-pack/plugins/actions/server/lib/get_system_action_kibana_privileges.ts b/x-pack/plugins/actions/server/lib/get_system_action_kibana_privileges.ts new file mode 100644 index 0000000000000..ef3b8ff853d17 --- /dev/null +++ b/x-pack/plugins/actions/server/lib/get_system_action_kibana_privileges.ts @@ -0,0 +1,28 @@ +/* + * 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 { ActionsClientContext } from '../actions_client'; +import { ExecuteOptions } from './action_executor'; + +export function getSystemActionKibanaPrivileges( + context: ActionsClientContext, + connectorId: string, + params?: ExecuteOptions['params'] +) { + const inMemoryConnector = context.inMemoryConnectors.find( + (connector) => connector.id === connectorId + ); + + const additionalPrivileges = inMemoryConnector?.isSystemAction + ? context.actionTypeRegistry.getSystemActionKibanaPrivileges( + inMemoryConnector.actionTypeId, + params + ) + : []; + + return additionalPrivileges; +} diff --git a/x-pack/plugins/actions/server/lib/is_preconfigured.ts b/x-pack/plugins/actions/server/lib/is_preconfigured.ts new file mode 100644 index 0000000000000..9f42c496d7cb2 --- /dev/null +++ b/x-pack/plugins/actions/server/lib/is_preconfigured.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ActionsClientContext } from '../actions_client'; + +export function isPreconfigured(context: ActionsClientContext, connectorId: string): boolean { + return !!context.inMemoryConnectors.find( + (connector) => connector.isPreconfigured && connector.id === connectorId + ); +} diff --git a/x-pack/plugins/actions/server/lib/is_system_action.ts b/x-pack/plugins/actions/server/lib/is_system_action.ts new file mode 100644 index 0000000000000..e21e1ee480df8 --- /dev/null +++ b/x-pack/plugins/actions/server/lib/is_system_action.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ActionsClientContext } from '../actions_client'; + +export function isSystemAction(context: ActionsClientContext, connectorId: string): boolean { + return !!context.inMemoryConnectors.find( + (connector) => connector.isSystemAction && connector.id === connectorId + ); +} diff --git a/x-pack/plugins/actions/server/routes/execute.test.ts b/x-pack/plugins/actions/server/routes/connector/execute/execute.test.ts similarity index 85% rename from x-pack/plugins/actions/server/routes/execute.test.ts rename to x-pack/plugins/actions/server/routes/connector/execute/execute.test.ts index 39319ff1dabf2..a9ae5e881f141 100644 --- a/x-pack/plugins/actions/server/routes/execute.test.ts +++ b/x-pack/plugins/actions/server/routes/connector/execute/execute.test.ts @@ -5,16 +5,16 @@ * 2.0. */ -import { executeActionRoute } from './execute'; +import { executeConnectorRoute } from './execute'; import { httpServiceMock } from '@kbn/core/server/mocks'; -import { licenseStateMock } from '../lib/license_state.mock'; -import { mockHandlerArguments } from './legacy/_mock_handler_arguments'; -import { asHttpRequestExecutionSource } from '../lib'; -import { actionsClientMock } from '../actions_client/actions_client.mock'; -import { ActionTypeExecutorResult } from '../types'; -import { verifyAccessAndContext } from './verify_access_and_context'; - -jest.mock('./verify_access_and_context', () => ({ +import { licenseStateMock } from '../../../lib/license_state.mock'; +import { mockHandlerArguments } from '../../legacy/_mock_handler_arguments'; +import { asHttpRequestExecutionSource } from '../../../lib'; +import { actionsClientMock } from '../../../actions_client/actions_client.mock'; +import { ActionTypeExecutorResult } from '../../../types'; +import { verifyAccessAndContext } from '../../verify_access_and_context'; + +jest.mock('../../verify_access_and_context', () => ({ verifyAccessAndContext: jest.fn(), })); @@ -23,7 +23,7 @@ beforeEach(() => { (verifyAccessAndContext as jest.Mock).mockImplementation((license, handler) => handler); }); -describe('executeActionRoute', () => { +describe('executeConnectorRoute', () => { beforeEach(() => { jest.clearAllMocks(); }); @@ -55,7 +55,7 @@ describe('executeActionRoute', () => { status: 'ok', }; - executeActionRoute(router, licenseState); + executeConnectorRoute(router, licenseState); const [config, handler] = router.post.mock.calls[0]; @@ -95,7 +95,7 @@ describe('executeActionRoute', () => { ['noContent'] ); - executeActionRoute(router, licenseState); + executeConnectorRoute(router, licenseState); const [, handler] = router.post.mock.calls[0]; @@ -131,7 +131,7 @@ describe('executeActionRoute', () => { ['ok'] ); - executeActionRoute(router, licenseState); + executeConnectorRoute(router, licenseState); const [, handler] = router.post.mock.calls[0]; @@ -163,7 +163,7 @@ describe('executeActionRoute', () => { ['ok'] ); - executeActionRoute(router, licenseState); + executeConnectorRoute(router, licenseState); const [, handler] = router.post.mock.calls[0]; @@ -192,7 +192,7 @@ describe('executeActionRoute', () => { ['ok'] ); - executeActionRoute(router, licenseState); + executeConnectorRoute(router, licenseState); const [_, handler] = router.post.mock.calls[0]; diff --git a/x-pack/plugins/actions/server/routes/execute.ts b/x-pack/plugins/actions/server/routes/connector/execute/execute.ts similarity index 61% rename from x-pack/plugins/actions/server/routes/execute.ts rename to x-pack/plugins/actions/server/routes/connector/execute/execute.ts index 74813a73474ac..ab5ed25ff5f78 100644 --- a/x-pack/plugins/actions/server/routes/execute.ts +++ b/x-pack/plugins/actions/server/routes/connector/execute/execute.ts @@ -5,37 +5,23 @@ * 2.0. */ -import { schema } from '@kbn/config-schema'; import { IRouter } from '@kbn/core/server'; -import { ILicenseState } from '../lib'; +import { ILicenseState } from '../../../lib'; -import { ActionTypeExecutorResult, ActionsRequestHandlerContext } from '../types'; -import { BASE_ACTION_API_PATH, RewriteResponseCase } from '../../common'; -import { asHttpRequestExecutionSource } from '../lib/action_execution_source'; -import { verifyAccessAndContext } from './verify_access_and_context'; -import { connectorResponseSchemaV1 } from '../../common/routes/connector/response'; +import { ActionTypeExecutorResult, ActionsRequestHandlerContext } from '../../../types'; +import { BASE_ACTION_API_PATH } from '../../../../common'; +import { asHttpRequestExecutionSource } from '../../../lib/action_execution_source'; +import { verifyAccessAndContext } from '../../verify_access_and_context'; +import { connectorResponseSchemaV1 } from '../../../../common/routes/connector/response'; +import { + executeConnectorRequestBodySchemaV1, + ExecuteConnectorRequestBodyV1, + executeConnectorRequestParamsSchemaV1, + ExecuteConnectorRequestParamsV1, +} from '../../../../common/routes/connector/apis/execute'; +import { transformExecuteConnectorResponseV1 } from './transforms'; -const paramSchema = schema.object({ - id: schema.string({ - meta: { description: 'An identifier for the connector.' }, - }), -}); - -const bodySchema = schema.object({ - params: schema.recordOf(schema.string(), schema.any()), -}); - -const rewriteBodyRes: RewriteResponseCase> = ({ - actionId, - serviceMessage, - ...res -}) => ({ - ...res, - connector_id: actionId, - ...(serviceMessage ? { service_message: serviceMessage } : {}), -}); - -export const executeActionRoute = ( +export const executeConnectorRoute = ( router: IRouter, licenseState: ILicenseState ) => { @@ -51,8 +37,8 @@ export const executeActionRoute = ( }, validate: { request: { - body: bodySchema, - params: paramSchema, + body: executeConnectorRequestBodySchemaV1, + params: executeConnectorRequestParamsSchemaV1, }, response: { 200: { @@ -65,8 +51,8 @@ export const executeActionRoute = ( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { const actionsClient = (await context.actions).getActionsClient(); - const { params } = req.body; - const { id } = req.params; + const { params }: ExecuteConnectorRequestBodyV1 = req.body; + const { id }: ExecuteConnectorRequestParamsV1 = req.params; if (actionsClient.isSystemAction(id)) { return res.badRequest({ body: 'Execution of system action is not allowed' }); @@ -81,7 +67,7 @@ export const executeActionRoute = ( return body ? res.ok({ - body: rewriteBodyRes(body), + body: transformExecuteConnectorResponseV1(body), }) : res.noContent(); }) diff --git a/x-pack/plugins/actions/server/routes/connector/execute/index.ts b/x-pack/plugins/actions/server/routes/connector/execute/index.ts new file mode 100644 index 0000000000000..6f5cb866722b7 --- /dev/null +++ b/x-pack/plugins/actions/server/routes/connector/execute/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 { executeConnectorRoute } from './execute'; diff --git a/x-pack/plugins/actions/server/routes/connector/execute/transforms/index.ts b/x-pack/plugins/actions/server/routes/connector/execute/transforms/index.ts new file mode 100644 index 0000000000000..5c245970ec914 --- /dev/null +++ b/x-pack/plugins/actions/server/routes/connector/execute/transforms/index.ts @@ -0,0 +1,10 @@ +/* + * 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 { transformExecuteConnectorResponse } from './transform_connector_response/latest'; + +export { transformExecuteConnectorResponse as transformExecuteConnectorResponseV1 } from './transform_connector_response/v1'; diff --git a/x-pack/plugins/actions/server/routes/connector/execute/transforms/transform_connector_response/latest.ts b/x-pack/plugins/actions/server/routes/connector/execute/transforms/transform_connector_response/latest.ts new file mode 100644 index 0000000000000..900d86f842fc6 --- /dev/null +++ b/x-pack/plugins/actions/server/routes/connector/execute/transforms/transform_connector_response/latest.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 { transformExecuteConnectorResponse } from './v1'; diff --git a/x-pack/plugins/actions/server/routes/connector/execute/transforms/transform_connector_response/v1.ts b/x-pack/plugins/actions/server/routes/connector/execute/transforms/transform_connector_response/v1.ts new file mode 100644 index 0000000000000..bc001cd9f9103 --- /dev/null +++ b/x-pack/plugins/actions/server/routes/connector/execute/transforms/transform_connector_response/v1.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 { ConnectorExecuteResponseV1 } from '../../../../../../common/routes/connector/response'; +import { ActionTypeExecutorResult } from '../../../../../types'; + +export const transformExecuteConnectorResponse = ({ + actionId, + retry, + serviceMessage, + ...res +}: ActionTypeExecutorResult): ConnectorExecuteResponseV1 => ({ + ...res, + connector_id: actionId, + ...(retry && retry instanceof Date ? { retry: retry.toISOString() } : { retry }), + ...(serviceMessage ? { service_message: serviceMessage } : {}), +}); diff --git a/x-pack/plugins/actions/server/routes/index.ts b/x-pack/plugins/actions/server/routes/index.ts index cccca87d849e2..5ea804d1ce47e 100644 --- a/x-pack/plugins/actions/server/routes/index.ts +++ b/x-pack/plugins/actions/server/routes/index.ts @@ -15,7 +15,7 @@ import { ILicenseState } from '../lib'; import { ActionsRequestHandlerContext } from '../types'; import { createActionRoute } from './create'; import { deleteConnectorRoute } from './connector/delete'; -import { executeActionRoute } from './execute'; +import { executeConnectorRoute } from './connector/execute'; import { getConnectorRoute } from './connector/get'; import { updateConnectorRoute } from './connector/update'; import { getOAuthAccessToken } from './get_oauth_access_token'; @@ -42,7 +42,7 @@ export function defineRoutes(opts: RouteOptions) { getAllConnectorsRoute(router, licenseState); updateConnectorRoute(router, licenseState); listTypesRoute(router, licenseState); - executeActionRoute(router, licenseState); + executeConnectorRoute(router, licenseState); getGlobalExecutionLogRoute(router, licenseState); getGlobalExecutionKPIRoute(router, licenseState); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts index 1ef7b170a4f0d..fcf0f2d84e755 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts @@ -246,12 +246,12 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { params: {}, }) .then((resp: any) => { - expect(Object.keys(resp.body)).to.eql([ - 'status', + expect(Object.keys(resp.body).sort()).to.eql([ + 'connector_id', + 'errorSource', 'message', 'retry', - 'errorSource', - 'connector_id', + 'status', ]); expect(resp.body.connector_id).to.eql(simulatedActionId); expect(resp.body.status).to.eql('error'); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts index 2268e379f441a..d41f8f1fcad71 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts @@ -236,12 +236,12 @@ export default function jiraTest({ getService }: FtrProviderContext) { params: {}, }) .then((resp: any) => { - expect(Object.keys(resp.body)).to.eql([ - 'status', + expect(Object.keys(resp.body).sort()).to.eql([ + 'connector_id', + 'errorSource', 'message', 'retry', - 'errorSource', - 'connector_id', + 'status', ]); expect(resp.body.connector_id).to.eql(simulatedActionId); expect(resp.body.status).to.eql('error'); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts index bd315edfb0459..0c5f52862b9de 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts @@ -169,12 +169,12 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { }); expect(200); - expect(Object.keys(body)).to.eql([ - 'status', + expect(Object.keys(body).sort()).to.eql([ + 'connector_id', + 'errorSource', 'message', 'retry', - 'errorSource', - 'connector_id', + 'status', ]); expect(body.connector_id).to.eql(opsgenieActionId); expect(body.status).to.eql('error'); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts index 6dfb420463e9f..232668c24749c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts @@ -230,12 +230,12 @@ export default function resilientTest({ getService }: FtrProviderContext) { params: {}, }) .then((resp: any) => { - expect(Object.keys(resp.body)).to.eql([ - 'status', + expect(Object.keys(resp.body).sort()).to.eql([ + 'connector_id', + 'errorSource', 'message', 'retry', - 'errorSource', - 'connector_id', + 'status', ]); expect(resp.body.connector_id).to.eql(resilientActionId); expect(resp.body.status).to.eql('error'); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts index 0f1748db4f5ef..c189580951495 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts @@ -416,12 +416,12 @@ export default function serviceNowITOMTest({ getService }: FtrProviderContext) { params: {}, }) .then((resp: any) => { - expect(Object.keys(resp.body)).to.eql([ - 'status', + expect(Object.keys(resp.body).sort()).to.eql([ + 'connector_id', + 'errorSource', 'message', 'retry', - 'errorSource', - 'connector_id', + 'status', ]); expect(resp.body.connector_id).to.eql(simulatedActionId); expect(resp.body.status).to.eql('error'); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts index bc0f48f15caf5..1f4f01db068d9 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts @@ -452,12 +452,12 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { params: {}, }) .then((resp: any) => { - expect(Object.keys(resp.body)).to.eql([ - 'status', + expect(Object.keys(resp.body).sort()).to.eql([ + 'connector_id', + 'errorSource', 'message', 'retry', - 'errorSource', - 'connector_id', + 'status', ]); expect(resp.body.connector_id).to.eql(simulatedActionId); expect(resp.body.status).to.eql('error'); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts index 717a44a406712..527ea53bbd1d5 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts @@ -465,12 +465,12 @@ export default function serviceNowSIRTest({ getService }: FtrProviderContext) { params: {}, }) .then((resp: any) => { - expect(Object.keys(resp.body)).to.eql([ - 'status', + expect(Object.keys(resp.body).sort()).to.eql([ + 'connector_id', + 'errorSource', 'message', 'retry', - 'errorSource', - 'connector_id', + 'status', ]); expect(resp.body.connector_id).to.eql(simulatedActionId); expect(resp.body.status).to.eql('error'); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts index 4d91fdddf80dd..93c2e4bc973af 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts @@ -327,12 +327,12 @@ export default function swimlaneTest({ getService }: FtrProviderContext) { params: {}, }) .then((resp: any) => { - expect(Object.keys(resp.body)).to.eql([ - 'status', + expect(Object.keys(resp.body).sort()).to.eql([ + 'connector_id', + 'errorSource', 'message', 'retry', - 'errorSource', - 'connector_id', + 'status', ]); expect(resp.body.connector_id).to.eql(simulatedActionId); expect(resp.body.status).to.eql('error'); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts index 04971990f879e..25b3b4b35cc76 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts @@ -188,12 +188,12 @@ export default function tinesTest({ getService }: FtrProviderContext) { }); expect(200); - expect(Object.keys(body)).to.eql([ - 'status', + expect(Object.keys(body).sort()).to.eql([ + 'connector_id', + 'errorSource', 'message', 'retry', - 'errorSource', - 'connector_id', + 'status', ]); expect(body.connector_id).to.eql(tinesActionId); expect(body.status).to.eql('error'); From e34876aa6809a5ea79a836ce61e94192a4769d59 Mon Sep 17 00:00:00 2001 From: Viduni Wickramarachchi Date: Wed, 16 Oct 2024 10:42:09 -0400 Subject: [PATCH 15/30] [Obs AI Assistant] Pass function responses when copying conversation (#195635) Closes https://github.com/elastic/kibana/issues/181216 ## Summary ### Problem Function call arguments and responses are serialized separately. Therefore, when a conversation is copied, arguments and responses (`content` and `data`) appear as strings instead of JSON objects. This makes it harder to debug. ### Solution Deserialize the arguments and responses and include it in the copied conversation object. Example of original copied conversation:
Click to expand JSON ```json { "title": "", "messages": [ { "@timestamp": "2024-10-09T13:58:41.723Z", "message": { "role": "system", "content": "You are a helpful assistant for Elastic Observability...." } }, { "@timestamp": "2024-10-09T13:58:26.881Z", "message": { "role": "user", "content": "Give me examples of questions I can ask here." } }, { "@timestamp": "2024-10-09T13:58:26.965Z", "message": { "role": "assistant", "function_call": { "name": "context", "trigger": "assistant" }, "content": "" } }, { "@timestamp": "2024-10-09T13:58:27.063Z", "message": { "role": "user", "data": "{\"scores\":[],\"suggestions\":[]}", "name": "context", "content": "{\"screen_description\":\"The user is looking at http://localhost:5601/kyq/app/observability/overview?rangeFrom=now-15m&rangeTo=now. The current time range is 2024-10-09T13:40:00.288Z - 2024-10-09T13:55:00.288Z.\\n\\nThe user is viewing the Overview page which shows a summary of the following apps: {\\\"universal_profiling\\\":{\\\"hasData\\\":false,\\\"status\\\":\\\"success\\\"},\\\"uptime\\\":{\\\"hasData\\\":false,\\\"indices\\\":\\\"heartbeat-*\\\",\\\"status\\\":\\\"success\\\"},\\\"infra_metrics\\\":{\\\"hasData\\\":false,\\\"indices\\\":\\\"metrics-*,metricbeat-*\\\",\\\"status\\\":\\\"success\\\"},\\\"alert\\\":{\\\"hasData\\\":false,\\\"status\\\":\\\"success\\\"},\\\"apm\\\":{\\\"hasData\\\":false,\\\"indices\\\":{\\\"transaction\\\":\\\"traces-apm*,apm-*,traces-*.otel-*\\\",\\\"span\\\":\\\"traces-apm*,apm-*,traces-*.otel-*\\\",\\\"error\\\":\\\"logs-apm*,apm-*,logs-*.otel-*\\\",\\\"metric\\\":\\\"metrics-apm*,apm-*,metrics-*.otel-*\\\",\\\"onboarding\\\":\\\"apm-*\\\",\\\"sourcemap\\\":\\\"apm-*\\\"},\\\"status\\\":\\\"success\\\"},\\\"ux\\\":{\\\"hasData\\\":false,\\\"indices\\\":\\\"traces-apm*,apm-*,traces-*.otel-*,logs-apm*,apm-*,logs-*.otel-*,metrics-apm*,apm-*,metrics-*.otel-*\\\",\\\"status\\\":\\\"success\\\"},\\\"infra_logs\\\":{\\\"hasData\\\":false,\\\"indices\\\":\\\"logs-*-*,logs-*,filebeat-*,kibana_sample_data_logs*\\\",\\\"status\\\":\\\"success\\\"}}\",\"learnings\":[]}" } }, { "@timestamp": "2024-10-09T13:58:35.140Z", "message": { "role": "assistant", "function_call": { "name": "", "arguments": "", "trigger": "assistant" }, "content": "Sure, here are some examples of questions you can ask:\n\n1. \"What is the average response time for my services?\"\n2. \"Show me the error rate for my services.\"\n3. \"Are there any anomalies in my system?\"\n4. \"What are the top 5 services by transaction volume?\"\n5. \"Show me the logs for a specific service.\"\n6. \"Are there any alerts in my system?\"\n7. \"What is the CPU usage of my hosts?\"\n8. \"Show me the network traffic in my system.\"\n9. \"What is the disk usage of my hosts?\"\n10. \"Show me the memory usage of my containers.\"\n\nPlease note that the actual questions you can ask depend on the data you have in your system." } }, { "@timestamp": "2024-10-09T13:58:41.651Z", "message": { "role": "user", "content": "What are the top 5 services by transaction volume" } }, { "@timestamp": "2024-10-09T13:58:41.723Z", "message": { "role": "assistant", "function_call": { "name": "context", "trigger": "assistant" }, "content": "" } }, { "@timestamp": "2024-10-09T13:58:41.784Z", "message": { "role": "user", "data": "{\"scores\":[],\"suggestions\":[]}", "name": "context", "content": "{\"screen_description\":\"The user is looking at http://localhost:5601/kyq/app/observability/overview?rangeFrom=now-15m&rangeTo=now. The current time range is 2024-10-09T13:40:00.288Z - 2024-10-09T13:55:00.288Z.\\n\\nThe user is viewing the Overview page which shows a summary of the following apps: {\\\"universal_profiling\\\":{\\\"hasData\\\":false,\\\"status\\\":\\\"success\\\"},\\\"uptime\\\":{\\\"hasData\\\":false,\\\"indices\\\":\\\"heartbeat-*\\\",\\\"status\\\":\\\"success\\\"},\\\"infra_metrics\\\":{\\\"hasData\\\":false,\\\"indices\\\":\\\"metrics-*,metricbeat-*\\\",\\\"status\\\":\\\"success\\\"},\\\"alert\\\":{\\\"hasData\\\":false,\\\"status\\\":\\\"success\\\"},\\\"apm\\\":{\\\"hasData\\\":false,\\\"indices\\\":{\\\"transaction\\\":\\\"traces-apm*,apm-*,traces-*.otel-*\\\",\\\"span\\\":\\\"traces-apm*,apm-*,traces-*.otel-*\\\",\\\"error\\\":\\\"logs-apm*,apm-*,logs-*.otel-*\\\",\\\"metric\\\":\\\"metrics-apm*,apm-*,metrics-*.otel-*\\\",\\\"onboarding\\\":\\\"apm-*\\\",\\\"sourcemap\\\":\\\"apm-*\\\"},\\\"status\\\":\\\"success\\\"},\\\"ux\\\":{\\\"hasData\\\":false,\\\"indices\\\":\\\"traces-apm*,apm-*,traces-*.otel-*,logs-apm*,apm-*,logs-*.otel-*,metrics-apm*,apm-*,metrics-*.otel-*\\\",\\\"status\\\":\\\"success\\\"},\\\"infra_logs\\\":{\\\"hasData\\\":false,\\\"indices\\\":\\\"logs-*-*,logs-*,filebeat-*,kibana_sample_data_logs*\\\",\\\"status\\\":\\\"success\\\"}}\",\"learnings\":[]}" } }, { "@timestamp": "2024-10-09T13:58:43.370Z", "message": { "role": "assistant", "function_call": { "name": "get_dataset_info", "arguments": "{\n \"index\": \"traces-apm*,apm-*,traces-*.otel-*\"\n}", "trigger": "assistant" }, "content": "" } }, { "@timestamp": "2024-10-09T13:58:43.379Z", "message": { "role": "user", "name": "get_dataset_info", "content": "{\"indices\":[],\"fields\":[]}" } }, { "@timestamp": "2024-10-09T13:58:43.998Z", "message": { "role": "assistant", "function_call": { "name": "query", "arguments": "{}", "trigger": "assistant" }, "content": "" } }, { "@timestamp": "2024-10-09T13:58:47.572Z", "message": { "role": "user", "data": "{\"keywords\":[\"STATS\",\"SORT\",\"LIMIT\",\"COUNT\"],\"requestedDocumentation\":{\"STATS\":\"# STATS ... BY\\n\\nThe `STATS ... BY` command groups rows based on a common value and calculates one or more aggregated values over these grouped rows.\\n\\n## Syntax\\n\\n```esql\\nSTATS [column1 =] expression1[, ..., [columnN =] expressionN] [BY grouping_expression1[, ..., grouping_expressionN]]\\n```\\n\\n### Parameters\\n\\n#### columnX\\n\\nThe name for the aggregated value in the output. If not provided...."}}", "name": "query", "content": "{}" } }, { "@timestamp": "2024-10-09T13:58:51.481Z", "message": { "role": "assistant", "function_call": { "name": "execute_query", "arguments": "{\"query\":\"FROM traces-apm*,apm-*,traces-*.otel-* | STATS COUNT(*) BY service.name | SORT COUNT(*) DESC | LIMIT 5\"}", "trigger": "assistant" }, "content": "" } }, { "@timestamp": "2024-10-09T13:58:51.619Z", "message": { "role": "user", "name": "execute_query", "content": "{\"message\":\"The query failed to execute\",\"error\":{\"name\":\"ResponseError\",\"message\":\"verification_exception\\n\\tRoot causes:\\n\\t\\tverification_exception: Found 1 problem\\nline 1:1: Unknown index [traces-apm*,apm-*,traces-*.otel-*]\"}}" } }, { "@timestamp": "2024-10-09T13:58:56.600Z", "message": { "role": "assistant", "function_call": { "name": "", "arguments": "", "trigger": "assistant" }, "content": "I'm sorry, but it seems like there are no indices matching the pattern \"traces-apm*,apm-*,traces-*.otel-*\" in your system. Therefore, I'm unable to retrieve the top 5 services by transaction volume. Please ensure that your APM data is being ingested correctly into Elasticsearch." } } ] } ```

Copied conversation after deserializing:
Click to expand JSON ```json { "title": "", "messages": [ { "@timestamp": "2024-10-09T13:58:41.723Z", "message": { "role": "system", "content": "You are a helpful assistant for Elastic Observability. Your goal is to help the Elastic Observability users to quickly assess what is happening in their observed systems..." } }, { "@timestamp": "2024-10-09T13:58:26.881Z", "message": { "role": "user", "content": "Give me examples of questions I can ask here." } }, { "@timestamp": "2024-10-09T13:58:26.965Z", "message": { "role": "assistant", "function_call": { "name": "context", "trigger": "assistant" }, "content": "" } }, { "@timestamp": "2024-10-09T13:58:27.063Z", "message": { "role": "user", "data": { "scores": [], "suggestions": [] }, "name": "context", "content": { "screen_description": "The user is looking at http://localhost:5601/kyq/app/observability/overview?rangeFrom=now-15m&rangeTo=now. The current time range is 2024-10-09T13:40:00.288Z - 2024-10-09T13:55:00.288Z.\n\nThe user is viewing the Overview page which shows a summary of the following apps: {\"universal_profiling\":{\"hasData\":false,\"status\":\"success\"},\"uptime\":{\"hasData\":false,\"indices\":\"heartbeat-*\",\"status\":\"success\"},\"infra_metrics\":{\"hasData\":false,\"indices\":\"metrics-*,metricbeat-*\",\"status\":\"success\"},\"alert\":{\"hasData\":false,\"status\":\"success\"},\"apm\":{\"hasData\":false,\"indices\":{\"transaction\":\"traces-apm*,apm-*,traces-*.otel-*\",\"span\":\"traces-apm*,apm-*,traces-*.otel-*\",\"error\":\"logs-apm*,apm-*,logs-*.otel-*\",\"metric\":\"metrics-apm*,apm-*,metrics-*.otel-*\",\"onboarding\":\"apm-*\",\"sourcemap\":\"apm-*\"},\"status\":\"success\"},\"ux\":{\"hasData\":false,\"indices\":\"traces-apm*,apm-*,traces-*.otel-*,logs-apm*,apm-*,logs-*.otel-*,metrics-apm*,apm-*,metrics-*.otel-*\",\"status\":\"success\"},\"infra_logs\":{\"hasData\":false,\"indices\":\"logs-*-*,logs-*,filebeat-*,kibana_sample_data_logs*\",\"status\":\"success\"}}", "learnings": [] } } }, { "@timestamp": "2024-10-09T13:58:35.140Z", "message": { "role": "assistant", "function_call": { "name": "", "arguments": "", "trigger": "assistant" }, "content": "Sure, here are some examples of questions..." } }, { "@timestamp": "2024-10-09T13:58:41.651Z", "message": { "role": "user", "content": "What are the top 5 services by transaction volume" } }, { "@timestamp": "2024-10-09T13:58:41.723Z", "message": { "role": "assistant", "function_call": { "name": "context", "trigger": "assistant" }, "content": "" } }, { "@timestamp": "2024-10-09T13:58:41.784Z", "message": { "role": "user", "data": { "scores": [], "suggestions": [] }, "name": "context", "content": { "screen_description": "The user is looking at http://localhost:5601/kyq/app/observability/overview?rangeFrom=now-15m&rangeTo=now. The current time range is 2024-10-09T13:40:00.288Z - 2024-10-09T13:55:00.288Z.\n\nThe user is viewing the Overview page which shows a summary of the following apps: {\"universal_profiling\":{\"hasData\":false,\"status\":\"success\"},\"uptime\":{\"hasData\":false,\"indices\":\"heartbeat-*\",\"status\":\"success\"},\"infra_metrics\":{\"hasData\":false,\"indices\":\"metrics-*,metricbeat-*\",\"status\":\"success\"},\"alert\":{\"hasData\":false,\"status\":\"success\"},\"apm\":{\"hasData\":false,\"indices\":{\"transaction\":\"traces-apm*,apm-*,traces-*.otel-*\",\"span\":\"traces-apm*,apm-*,traces-*.otel-*\",\"error\":\"logs-apm*,apm-*,logs-*.otel-*\",\"metric\":\"metrics-apm*,apm-*,metrics-*.otel-*\",\"onboarding\":\"apm-*\",\"sourcemap\":\"apm-*\"},\"status\":\"success\"},\"ux\":{\"hasData\":false,\"indices\":\"traces-apm*,apm-*,traces-*.otel-*,logs-apm*,apm-*,logs-*.otel-*,metrics-apm*,apm-*,metrics-*.otel-*\",\"status\":\"success\"},\"infra_logs\":{\"hasData\":false,\"indices\":\"logs-*-*,logs-*,filebeat-*,kibana_sample_data_logs*\",\"status\":\"success\"}}", "learnings": [] } } }, { "@timestamp": "2024-10-09T13:58:43.370Z", "message": { "role": "assistant", "function_call": { "name": "get_dataset_info", "arguments": { "index": "traces-apm*,apm-*,traces-*.otel-*" }, "trigger": "assistant" }, "content": "" } }, { "@timestamp": "2024-10-09T13:58:43.379Z", "message": { "role": "user", "name": "get_dataset_info", "content": { "indices": [], "fields": [] } } }, { "@timestamp": "2024-10-09T13:58:43.998Z", "message": { "role": "assistant", "function_call": { "name": "query", "arguments": {}, "trigger": "assistant" }, "content": "" } }, { "@timestamp": "2024-10-09T13:58:47.572Z", "message": { "role": "user", "data": { "keywords": ["STATS", "SORT", "LIMIT", "COUNT"], "requestedDocumentation": { "STATS": "# STATS ... BY\n\nThe `STATS ... BY`...", "SORT": "# SORT\n\nThe SORT command...", "LIMIT": "# LIMIT\n\nThe LIMIT command...", "COUNT": "# COUNT\n\n....", "SYNTAX": "# ES|QL Syntax Guide....", "OVERVIEW": "## ES|QL Overview\n\n### ES|QL....", "OPERATORS": "# ES|QL Operators\n\nThis document...." } }, "name": "query", "content": {} } }, { "@timestamp": "2024-10-09T13:58:51.481Z", "message": { "role": "assistant", "function_call": { "name": "execute_query", "arguments": { "query": "FROM traces-apm*,apm-*,traces-*.otel-* | STATS COUNT(*) BY service.name | SORT COUNT(*) DESC | LIMIT 5" }, "trigger": "assistant" }, "content": "" } }, { "@timestamp": "2024-10-09T13:58:51.619Z", "message": { "role": "user", "name": "execute_query", "content": { "message": "The query failed to execute", "error": { "name": "ResponseError", "message": "verification_exception\n\tRoot causes:\n\t\tverification_exception: Found 1 problem\nline 1:1: Unknown index [traces-apm*,apm-*,traces-*.otel-*]" } } } }, { "@timestamp": "2024-10-09T13:58:56.600Z", "message": { "role": "assistant", "function_call": { "name": "", "arguments": "", "trigger": "assistant" }, "content": "I'm sorry, but it seems like there are no indices matching the pattern \"traces-apm*,apm-*,traces-*.otel-*\" in your system. Therefore, I'm unable to retrieve the top 5 services by transaction volume. Please ensure that your APM data is being ingested correctly into Elasticsearch." } } ] } ```
--- .../kbn-ai-assistant/src/chat/chat_body.tsx | 5 +- .../src/utils/deserialize_message.test.ts | 118 ++++++++++++++++++ .../src/utils/deserialize_message.ts | 35 ++++++ 3 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 x-pack/packages/kbn-ai-assistant/src/utils/deserialize_message.test.ts create mode 100644 x-pack/packages/kbn-ai-assistant/src/utils/deserialize_message.ts diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx index c3989f6971fff..5b80a34e0bf7b 100644 --- a/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx @@ -45,6 +45,7 @@ import { SimulatedFunctionCallingCallout } from './simulated_function_calling_ca import { WelcomeMessage } from './welcome_message'; import { useLicense } from '../hooks/use_license'; import { PromptEditor } from '../prompt_editor/prompt_editor'; +import { deserializeMessage } from '../utils/deserialize_message'; const fullHeightClassName = css` height: 100%; @@ -226,9 +227,11 @@ export function ChatBody({ }); const handleCopyConversation = () => { + const deserializedMessages = (conversation.value?.messages ?? messages).map(deserializeMessage); + const content = JSON.stringify({ title: initialTitle, - messages: conversation.value?.messages ?? messages, + messages: deserializedMessages, }); navigator.clipboard?.writeText(content || ''); diff --git a/x-pack/packages/kbn-ai-assistant/src/utils/deserialize_message.test.ts b/x-pack/packages/kbn-ai-assistant/src/utils/deserialize_message.test.ts new file mode 100644 index 0000000000000..b2c067a3e9f10 --- /dev/null +++ b/x-pack/packages/kbn-ai-assistant/src/utils/deserialize_message.test.ts @@ -0,0 +1,118 @@ +/* + * 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 { cloneDeep } from 'lodash'; +import { Message, MessageRole } from '@kbn/observability-ai-assistant-plugin/common'; +import { deserializeMessage } from './deserialize_message'; +import { safeJsonParse } from './safe_json_parse'; + +jest.mock('lodash', () => ({ + cloneDeep: jest.fn(), +})); + +jest.mock('./safe_json_parse', () => ({ + safeJsonParse: jest.fn((value) => { + try { + return JSON.parse(value); + } catch { + return value; + } + }), +})); + +describe('deserializeMessage', () => { + const baseMessage: Message = { + '@timestamp': '2024-10-15T00:00:00Z', + message: { + role: MessageRole.User, + content: 'This is a message', + }, + }; + + beforeEach(() => { + (cloneDeep as jest.Mock).mockImplementation((obj) => JSON.parse(JSON.stringify(obj))); + }); + + it('should clone the original message', () => { + const message = { ...baseMessage }; + deserializeMessage(message); + + expect(cloneDeep).toHaveBeenCalledWith(message); + }); + + it('should deserialize function_call.arguments if it is a string', () => { + const messageWithFunctionCall: Message = { + ...baseMessage, + message: { + ...baseMessage.message, + function_call: { + name: 'testFunction', + arguments: '{"key": "value"}', + trigger: MessageRole.Assistant, + }, + }, + }; + + const result = deserializeMessage(messageWithFunctionCall); + + expect(safeJsonParse).toHaveBeenCalledWith('{"key": "value"}'); + expect(result.message.function_call!.arguments).toEqual({ key: 'value' }); + }); + + it('should deserialize message.content if it is a string', () => { + const messageWithContent: Message = { + ...baseMessage, + message: { + ...baseMessage.message, + name: 'testMessage', + content: '{"key": "value"}', + }, + }; + + const result = deserializeMessage(messageWithContent); + + expect(safeJsonParse).toHaveBeenCalledWith('{"key": "value"}'); + expect(result.message.content).toEqual({ key: 'value' }); + }); + + it('should deserialize message.data if it is a string', () => { + const messageWithData: Message = { + ...baseMessage, + message: { + ...baseMessage.message, + name: 'testMessage', + data: '{"key": "value"}', + }, + }; + + const result = deserializeMessage(messageWithData); + + expect(safeJsonParse).toHaveBeenCalledWith('{"key": "value"}'); + expect(result.message.data).toEqual({ key: 'value' }); + }); + + it('should return the copied message as is if no deserialization is needed', () => { + const messageWithoutSerialization: Message = { + ...baseMessage, + message: { + ...baseMessage.message, + function_call: { + name: 'testFunction', + arguments: '', + trigger: MessageRole.Assistant, + }, + content: '', + }, + }; + + const result = deserializeMessage(messageWithoutSerialization); + + expect(result.message.function_call!.name).toEqual('testFunction'); + expect(result.message.function_call!.arguments).toEqual(''); + expect(result.message.content).toEqual(''); + }); +}); diff --git a/x-pack/packages/kbn-ai-assistant/src/utils/deserialize_message.ts b/x-pack/packages/kbn-ai-assistant/src/utils/deserialize_message.ts new file mode 100644 index 0000000000000..445e6330981a9 --- /dev/null +++ b/x-pack/packages/kbn-ai-assistant/src/utils/deserialize_message.ts @@ -0,0 +1,35 @@ +/* + * 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 { cloneDeep } from 'lodash'; +import type { Message } from '@kbn/observability-ai-assistant-plugin/common'; +import { safeJsonParse } from './safe_json_parse'; + +export const deserializeMessage = (message: Message): Message => { + const copiedMessage = cloneDeep(message); + + if ( + copiedMessage.message.function_call?.arguments && + typeof copiedMessage.message.function_call?.arguments === 'string' + ) { + copiedMessage.message.function_call.arguments = safeJsonParse( + copiedMessage.message.function_call.arguments ?? '{}' + ); + } + + if (copiedMessage.message.name) { + if (copiedMessage.message.content && typeof copiedMessage.message.content === 'string') { + copiedMessage.message.content = safeJsonParse(copiedMessage.message.content); + } + + if (copiedMessage.message.data && typeof copiedMessage.message.data === 'string') { + copiedMessage.message.data = safeJsonParse(copiedMessage.message.data); + } + } + + return copiedMessage; +}; From 456e9b81c2f6ed7bb880fadef342a3ee1cadde6d Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Wed, 16 Oct 2024 08:18:28 -0700 Subject: [PATCH 16/30] [DevDocs] add developer documentation for updating puppeteer and chromium (#195337) ## Summary Add documentation on updating Puppeteer and Chromium --- .../shared_ux/browser_snapshots_filter1.png | Bin 0 -> 57864 bytes .../shared_ux/browser_snapshots_filter2.png | Bin 0 -> 75522 bytes .../shared_ux/browser_snapshots_listing.png | Bin 0 -> 181608 bytes .../shared_ux/chromium_version_command.png | Bin 0 -> 140479 bytes dev_docs/shared_ux/shared_ux_landing.mdx | 5 + .../updating_puppeteer_and_chromium.mdx | 136 ++++++++++++++++++ x-pack/build_chromium/README.md | 16 --- 7 files changed, 141 insertions(+), 16 deletions(-) create mode 100644 dev_docs/shared_ux/browser_snapshots_filter1.png create mode 100644 dev_docs/shared_ux/browser_snapshots_filter2.png create mode 100644 dev_docs/shared_ux/browser_snapshots_listing.png create mode 100644 dev_docs/shared_ux/chromium_version_command.png create mode 100644 dev_docs/shared_ux/updating_puppeteer_and_chromium.mdx diff --git a/dev_docs/shared_ux/browser_snapshots_filter1.png b/dev_docs/shared_ux/browser_snapshots_filter1.png new file mode 100644 index 0000000000000000000000000000000000000000..75b04ac16889c2842bdca462d5e4904c79aeb5b7 GIT binary patch literal 57864 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%0A4zCeY|KP<|9B zIdhLy*IoSiq+v;K%v5U6xzRfpQL1=Eg@h1yN6g12eqAy%qC?ZLCXQt0S-ame3HyUvnbb}&fW5DECT+ZMXz*+h4+@Yq07>wXJcmkPySH(+=3IPTgz-yiR#4aJP!fv z0_6N-rp%E^4e)k`D|bV#Fe;Q_c^7=RkoJ}89cwj2Ie+ivgacV{xKwmzIiP2>u<6=% z)#KdbW?6hr0jG?|9GFO{F?@_xMQ1ZA)ELyBNWK_E3npCHft7vRVpZiVjB0vhIl0_- zG2bdf1UIh>3;NhK0#e0mVypZelus8Z4mCMDz5^Tr$B(qTbk(vWDaxCqtvBIG?~;@y z-#YzdvB*>1zcz$C5>>hq5>f3lU}ONFwmRITj_@iJQ`+62OCy@tTB(*i1IxM(^I^@d zR2w5(I0eDlC0*Jd)}xn!sx=j9m-3-Um_S+mjQ1`vDe+UCrFehR4O;I|DsJeG%tYdqs8Pwxh zqElVuEL;Q7gq(qlJ?OptP!cog0_iO62T~^*%8txUcPWaAHZa(G;oWRkkPgoN*~aIU z+gw1aqY{2P%sm}o48{)rd)Uh(Xy;EMuetvldU&_y701Nak1%C z54|66^UK_A7|WYnrkKJ!${am4q!z#u7$M;VTn z&+BpkFSXt2Vx)JDAFccYGnFPsmCy4wiIoz|+NZVg~RqMf1yL6nldz-28(%S#%dwCVQ)7Cau^dN~p>w7Lbp3ImXAyexa`PUwsSE zL*C8#=K$e8f+#K3;ucSL>pXF2O7YHMAq|4CkK`T#j*J>|5LdOjWG;&?I`TwKo*+xL z##zF;1nhSkjX{=^RY~tz(}v}`{voyN`p1bli7Kd_)}@ILit^%d`KTZ!iOd~#b1Lr_ zGkvcmgm?`CIWj`wFPZr(bOe`xnuqW321K<&Sln^blPlHQHIKy^w-%V+xmn7aWH8Gs zn9S-3E3t%f^c0A;Xpbpil$v?ygLlHWE?U;w zTT0PCH1%h(nr6RCv+_1r?WsC@FPAy*ycxKSbnrEd>z=&}>EVOANtaNiWrt^wd&{yq ztUUvDCw$wPc&fS9SRk8O&?}c3wlrpPqxWgW)PV#LibH;&<36XH7dd{sCj@m1cE6sh zT`rEiK|8s25U@$hG#LH^_!|>PU?k@nVCoS{Csi0D@tbD%mn0j?ozTQ_$SPC=LZZ*O zGmS;cnfMrVUH0euidX&70aC!rB+a6nmpam2wNCMYwP_d_f<{8L40a3y`W$I0 zGlp%m(irRZn({+-;-QBoSrTpeMV*azZ|vy;A{4EnAvy{lmsH5@w`T3<{c z_(u3kYnC*p$5*Gp3ijae9H9Vm1(pSPCHC$ZEBagOq){R*!Dp%+W7x=(<2P4V8qE6I zkkDEzFFpSwKTs>~NS6@@X=K2J38kZ9b5x6gw6~|L($?Uj-CH6LS)<6WaWIh%;B!N;ROf;v($|EEh!QudWk&9rTuS{@>TESykD-2B-(mvk~PWB3`3850Oy&h z=LMOmOLk(5jD>Lh2TX?hB+;#a!R5@^s$1L}r6jhVJYYf7O)RE&rxT8c69eU-xU#5?1pFiW_tFJvVWeO$@3J6{Q{I(2gww0oE%xSeg_en^~OK-leRRR zeS?G$oc^S)dRMGi9#34&UFr>K9rh+3;c4)8K1gz-6P;t2@pTJ%vt2kW9h@HGSvU|Ie0(g_lj@P1^I}K20O@sBibdWF-3A{ zq)z)pk>*?y$(>j7Z-SXcc+QN;&zRFpX6N_#Jsl(w`FVg`D5PBTN0kHK;qfZz>}X&c z&Z~cU*oB$oT)KXy4H=9@Re=kKL&ZWt!htY(fOi69MQlwMhK654qxe*FKN<2c^^wLE z9EOruD^&#g& z21eLPB7Ib3teD;1cIWkb*eKGFP8wWPYr}0Ml)4bdJUZG&Zub%=kt1}^RGPbt8vJN_ zo&U0{D-}Y-IDqtj^yE;_t)n4ZZbP?9x$o1@9{s=S29rh~v@BRYc#g*d0_-DAtJDEh zN&vgIRD?C|kI~K3pwC0EqS^k;f| zf)ij1yiBF4XUMzRUN~o=Z1k5zx!_&o5&jel= z^!e3x0{P_JGary$KN9&hhdMCH@WE1IszoTk*e^Iez>E16kQ8d9yGzz9o)u*JsFyf< zL2g;VabQN-9Kk>rgQs&vx?HguSVh)qQxqn9G!6=A@IRHkz>+gDd(;-P*8PmT_Vr$g zr*P>H_8D&X_;y}{#qJb!884W;;7(jGE-9d!EvM)t(o8;t=@z7 z-@hl7kp;plk?ykJpHCATMau%Hq$qFGalbr0VB5HR0GqCHx8Fmjsv!buwNS0+=toU3 z;p^{r6vcVYFD%PI51%aFI=&$=l;|5hRO6GRkmPTUEe$Q6>DyZ3}O@ zK2Ix!o!LuNTH;m=h4f(tcsu~=AY=vS^z3+Z8|*3P89g_D1OYL%BQjc6EII}-ti~s% zY2@D6dmpuaWDoqQ_7n4D)ng4qyn^$lH9k~0^wF3;`&8olYlO@TFlBn88ym9H5*eNl_q1wPD ztlE7f=Yi^5$71I}fl#5InPspzO?>D)=ME2ytMw_q<)h#uV-)Y|8IzZ0(KB??mo*pRrs@DS5fccfD})gcC6y?>M`^j(>22NgCZ1u< zh~;!$%x4eg*M)q120${1>jM2LfN`x@(R!Kx>qQrYhctlt>w8+TFT4kCOvuHs@oB@S zVP`={yKxIt?y~svXeL*1GZAZEQcJYwns8eOzym0Qh&5ud?c}oYn)bp9rim9a@T}Rp``~?54n51=XUuE`*@n+xFN`9EC-zNWFAOKGW%xqaoc=FIxa9?>ioR zfmKG8DIKx~1)W9Q0K;cnH zz2I*AnBc9DsM5qHjT)!RXNvX}k1cH1;mO*(e#*T69?`InJhWajQlt~%QI`%jCbz)$5cTL0JYzP|rDS(B%k9e}S)DA~9I>AvINFH|MK1nA3t zw2}`7VWeLjglJ8=2z~?F;Xt~q7)A%JBNvQOvS!s!ahvwTCSn1u1^}5kG}Bj5BTr^| zzjTtapbzU|FDW!wai(trqy^X!z$zn3hye*X)q4}TZwqqG8)VeWp|uAr!9p=y3-& zx6vadv8T+`*ff$KJ6K6kRZ*}%e3Rq|PY5KpeiT5`gW}Ji#O$ZDj8ypUZVo>h8Tm7E zqD_b?>->~>H|6ONNs*(npv4xR}OC1tU**q{)+GtKr- zLC|Opo#nk{VEL6iE?(VgTbR||dib;LBKd$~Z0Dkd`G8>9hUK~Pr}D6Xl}??oTmCx5;tz5syx%{IhAcIv<*Jtr z!np`tRZ z@?zh#E%rw>hS++!b-qt`XYSc|9#{2URllMO{5VNr-4&^#t@=qNZM=qs?vs>3xF3Vq zcPD3AxW8eMu83jA>%hY^-gL2i_aIDMiIzI_^JCkVk=?|i@PzFh3UXyX!wdq|c?Ump z6AvY}{XudERjwr&M?-`kbM5(}gQlY7G$tWAqNk-1E!as@No9a!od}nLe4;gBr*@}- zjBKl;6orp}$7&5~i5XYkv*dD$4C8?kv6yw@dQjY+S0h3^#&SL6)19P7^sTz4=$H7h zt$37lf1CQ|@>%5=gdX(o-7`9*e5sp6Po|BJ`Y0m0Ze13tClCx1e)47RU4bn>-2^*+)B3tJ zBiRHADIF!G++LK7pG7vg#zKt1ZIfd=v8lTCF$FhLE8f$y(edd!HV7er7#O zPhi0wIPYgwxf^C!mYzKG)iNCMEcdRthN}#nDD&SNdUf3i$(tAQ)J_|{wiu(>l1_X1 zj)5dyc_LvTOZct8OUFQ!^vabc1f4Qu-_I%=y#@1htotNeJ8l;(Z#gU}blJmPDZ5yu zXtAW?rGdxa6#l}COOCMkB{6YDDig7VhQW9v*`i*5^b5GtZIu*y**eQ)L{gHjyKdpL zjAcppZwz03cCHS@^DbnTCZ3fFMuERG&x3VsV zh*F=`qcoceAyL#e_aM1BtEJQzu(7los6rDBC7ZZ_|KO`v^q0XyTo=;>DkEa?h_`cXb zMK4i>;k;NHFEgjCu?1mE4_P4E!_hvf_ukBr7GlqR@>cQy^B(WkKac2Tx0!v*uq{5 z(VEFlHUk%BcN{tR`?s*Z=N<55oypEZF!FJTGj6GJGKQcbN|eI=Np^c{<86ZCy~6$t z?Z{gG$H9sa;ypZnWiKb8Jzfg_&7Ah7U~nI4{0I8NzkRQKCscjL2ruM5z)IPRlw}Tw z>)7FGZ7sYD%lDtd&ep>{OC5ZQpIlH7dDEk#T`VDkitPE8sdO`^Mj7nKCGkQf!E;_- zAwOj8U+oAKw#Dpm-NoB;Xu)QMuFDrB>GN6!>S9lk1TVd8>!wfjgzxgLiCAn2Fq!Fx zR&dZr{CzM`kFvr^69=vdHqxy5mB-)y{d{!nKWWF5eq3mcfsqlGN!+GH^6S^-Pi2GG z9IWSXHKJ|LByDu2AnnmJ^g#L8S9y(%clMM5G?i>UQ>W)pT z;$hXa9HE51BzpWxWPY!n%R<0;phUi=8qed$DM8$E4Zrix zf*2W=gAT^%)Ki&|=cn#xtg_cBGfMKBEzb*m^07JojC*KIc1=k_xQB|a@LmJ)hjT{D zPXD!A60z&UVb7!vcU}DZF3)96}|HsxZEqr9}Hd9IIhTg}r=*CX$zI1cj$=c^*WcYF3 z@B`xy{lzY&42~L_fRwI4_cOtTZFN-OM|iSyzh+q!+*IxJFWyntx=zIUVr*E>LBsX%a5?-O5!y`Hy@)a;QN3@3)^!k6-`f?T$!+!`9?9WN-fs^#WCRAxrQg_FmtpK9R_-eZ%3hCW^L4{aMqpdFtI* zzRUjh(Ik?2GXT|<3ZeSK&yiUF{6d_6A&cr+b^eMy9)+2_cT(9muS6zf%-tAz3l>$L zm(WWM^Rq)=N4H&4;=O?tMHKPk8<~nB*toG>^p=OZJ9e=ycb3AgyjoX&ncK1_Mg7%kJ>G*79cxJ-kO(#$hv-m4CNoid(WsGi%0vPkG#r5rgW z&u}%M7j)?mHx)A_ zo$Svq7BB(b>j{?)xKoD-6wB;0kFY*^Bsc;7D5jdN?i)lQ)y@>`Y7--HtSQM6Lc z(6vt<4{J5hja# z+NdPDAFVN~YV$lf=f@rn?9x5!Msq0bPgt9JuXPiuvbz1f5PK{p2(xLe zQNDb^)8xpuH;XtqVtsq8lgA$}Vqu;o=}TJf-uo+qt0j^_t-VX>LD%?N)3XY7>d|*e z{)-#o2V6t&dL0yTLv67=^3Ly>Q^v!W%?bzR(jkf3iTTbei;qhrLkwBY_zsKVglHvu!T zIc(LNcEx0jKK>i7eEH9I3}PDor_Y%59mZk~y0~CNbr_U8QTfOzsvAavZwgJ!L$VT? z7j!e3neM{pa+53?_TrhoN6*0xR@KPt-T8(9yp~%dSm>`z4=y=-=Uo=eTCZ^a-QJR~ zWA;%NNp8P&-%M>AzWQF2Rqg2l@VP~D&YlbFA{x$SJd!!TcpHnz&Kb^*LtgC*a?Vnr zAe8cM=jomKXSkPnJ(x-; z6v(5rkfMX!H2kw54i&v!r>(rSf_Kgc8sc{*GJYg<1+Kr@zKC65HvPHaxwj;cPqCAR z#13XrS$SkRJJB$-sQp;f?zL>AR1oeHzW37VeY=~jrx@P)je?HUq$%2ZL8r|txPk6x zi!OP-J=#))vqBU<1EJ$_w-nLN)%d5heJRLJ)L}~q_q-;7P5i)Xi>n10-%?Nw8X zJ3;H8@9h>D7OY~EN~V9bj*j|#kzZX2wn01aOwn84PrkBKs<2zKDGAXlKQkM;m18m_g1c;S4R?Z z8_pI@$iqKeO=&2ctqdCK6KYGJMh)dyc!olOJ@YicITWq-eFjQr6!K^R@j>(k>T30_M4C+I_;@ zX9`*e1#PtZ2cUuK*y4I0AfJmS+WcJB>9fx_@N2wd^z;iBuI2rl&nQW;&Y^&`FGO1( zUcIB|HjPyuh*xPX;5r5mh--SO&zSH-uO9#GL(D)J!dr_?QjpWTt|g{^MFM$Ofnl=n$B8zB;Dns8uH5T=9BlF=oS}sOtfe%0q$0SN;*vK;4zZJ$8_2Ha&AX|UPHg^ zT}#VazOUjyaM=r6OJL8~x`0c2>qGoywiz~P!|#2TM@VY-Hz!#xJp*cWrw3}6J!FH; zY5A$LB@&TekVg$tObfGc`Y%F)?ZC@Wq~^L!fiEiGfDEIupe>NWfmQ+$pU z*ZFdFKPAIfqftZ!Y8N~9FkWXGD4s=rD;pD`rL~bi1K~xCvOl@Kb%utzH=qLJ#OkA=!S1>>6cZSh6xKS9sg>4b+M#5 zo8zx4M|5Abm8~so(_k9luda9h>fH5=3J65xp=$fc{jo_}SsK6dO!TJ1{NH z@=4q8xIVCN-e^IVQ_D_v!-H&LmixE(OJ&pYb>izQnQ2uY*up5CKJI)owGyjK?4V-P zvSMrDUpd#6aMp~ylKaytm}?7L%AdQxlcT*GhRLDUoQrY-&ewhkGSz=WsC;FCo%s6B zJAbrN9iWAqhTX&*iP^pN^iG<0IWQY(JE23sG78PlwikHYY<1G!NhI|!3neM(2OonF zvmVGYw6GiaeMZ06&G7!mMg;$eJ)W)x!nSOOORmn!`Qhx;w z&m_JcgCq>i=wG8rUwAN2djy#*8K`&hEf$4$G1@%0vUJ*R=-6|pzGz9_E9{(kJ$X4K zmDPyD&|d3t(Z==4>@dU|bGt%?8dHizDGrHYbGxVQR0d}JS1HQz-f4kMgznqv(e0i{0Dy3kxKRxDD zj)>3wHQ%rQ{Vu4#it3=C2CqYNU;ZD>6s49h7*3`7Gxnn?Z%8h~rgdrN@~Y+rYR(z- z&t0E=`r5AOXTV7MU!Lz@ZE!m)Lvztv8AN%_pZ@uqF4sBqzciN?Xf7*wK>tF?H4th{PZo@0{HK9gqCktWQDv(Bd4zvjL;bZ~t;@dVVGhIO z*jt9!M9(y#mv?>m=R|5&;FCCjmGS=*2>*(Pe;;CKKI`mc)ZLaOFgnK3?+mA#rr9Xd zyVI%sa}QBJR7_kF%tWK7|NRYTHKVBmb_JB)x0ZgG55r!*Tm#oZAKSbMm-12!Rf zxJum5|KY3Zqu%k~<24zytNFcJYRWLs(3uhWzdrRS^BkjT;|T2cYF6j{7=QY2;s5JX z^94D(?k?dxPlQ-0t^^iZuj~8{DhdDjh@mRLSN)zE|Gz);|K~;h^H7-am5=HQR-+ZmrZ`NU+TH<+I(-r}H2qi(R@rVC&^aENB26`Wn)U}*fPa+aDUp z-!<1Q*S{}0fP1YHTP&?>aNkWV*);V!dpkat_@6G3<$*;=UaYsnbvo|!{FYxV`aZxc z?rlI&M9NoG6e&?k2N94?Q96cJ8kH^`N}53(R1i?YLkTED3Mk#67&M4Or=+xifb?&T z$8*km9Y?S4{rls;ad7st_u4D(d+q(OWEz?u8YAQgv=4w+Z5z2ThN4f)yi>y1hTFZ; z`{AgavDo9G&fOsM&OuV$P0!3e;Ze4j`HjcMeb(njGEGb6o)e>?B}(pqaFD!XBz5DX@NM!Fk!uFzQ2YoJ4TSi^IKtKgTVQzdC)HiAM z%he>&iIXmpBGE$>*QHKp33l7j#)9 z(wJ1(wm*OQ?g4{Arhfi;$CQH|*(P(bJx9;kT&l)Usm5#UiK|wZTz%7JS2|OW8-31J z4)OZ(Hk6b3@IHvj#E@;N?bQ&3K|zCHpR-oVtcKg#=E^`%UBs!l&9opKx(b<2{*nCl z;hGg6dLQ-Y_Xw!DpL83Ac6}9cduwwB``GyY=^m`|;nL-9+nG7v?b4;$J~8X{!hVnX zz2`Y;bKp?pNkoi*^`n{cmHz&+whTQnG>zN4u^2}tuIob%dY_xUm~L|`-1zcpkC;x` z{5ytB*#K&E+vdh%vwd&T4Hz}MD_tj}%q2$1(ZTYGdvcs}tD)kl`T%U$kOCL5bWl3$<6z?wJ2uUbj-Fj3Ep$(Z&9&Ocd9+xM9MN^D!Z~@ zO?>`MUPiV-Vbj*P_fp+&?j0yM4cFB+wcOrZDGcN(snO4~dgyAWSCS|3Dt9QFNtha_#YwCu4u2> zfG%ZAs-NuyEJjJ*uPSuT5N_FNmG!~qIt5J9(Q8iTy=U@lkb7`+l<5f>875qCwrDtb zQGfLqs)n__!rN0zRER9d*lYe`c5E=C7<)tp*;czmv~G)iy!Y}A%^a@OVfEFNc4N_i zC=9dDw^wo@O!m2!&C9yACwT>~4@#eTk>t-uhQUxXPUam#xh1ztfWD)$9)S8bFMkSP zE(wfXDj4wbbkvu@&i0jhW(I+IFif>&Jm%_4)K|Cm6yn9|>WOkVC>OZ(yT3mbu%DEc zoCDlK>;YR=d{*LXWcsR4lxUona=$_8V0rVFrH(ndOWdCW!P;X!mNI`UB5mV%0KHj8u;mN=hvucdB zR{EWC9B#WA?-VMWHe@1kGu4vhI`@UheEFzk(5(4`8uj#8anG&Q@l1!ll8F2Bh0miz zUD9VN)@PeUmAYKNeF_j84q$ZsgX`Nv2jq(ydx_y?ve7KJPj?Qp=PRMcOXD?2WR)ND zIo$F>Im#zo>du#DK-3E*uGI}vX;5wUJ z(3ePDx=#Jq1Y?8|s95-rZA~a^lVBRn7=w_5-I{u}AMq|bIA8DbZb>R4C1-oBqp~~3 zv0|cezl_xv0=SWqz=0kiti*5{;9b&VIdlt!Q6Y(_M zVfOkfvctm9%$RTE{f`=B-^@~)bWjWhLd#SkQ@{7B&YEyOlaf%-5&n0{Dp5nHOV(#g zX9jQ4xV|&--E>LWibj4(l@DQR+Q4lWzv5_o{LCLYdmUybve;|wo!;-j!ewWwAS1SP zILRrArD^oBiNj=vf^11u%j-M)%6+i7<4UjMa5CfbLY1oz_{GkBIZ0D&rJz?amN9#4 zH&tuu;>23Av2PQ_1`RPO3EAs@nqB+MSPAF}q>_FR>jXGz&EP3M!+Dyh_-gy@NAs@L{wF(x zDIaJ3;prV;ElaP}g;Cdrv+sq6`7~KLdlDjrDc)I=Lu*R0l6lJF{I}td7|pjXlek(g zHlsng_t>rQ_UD(cPBJU>;L^0-Umn;TIG`?Wrf1|5!Jh`)tyT>qU2J&ZZn6Zq;A0a! z3z7je%(LMcN4N)OOzu^M%D*8eNhDh+X2$gIJw-5mMv{PiwZ`7QLW&9J!@EG`+?B7n zvt^5F94!f0(CUeT^vNn@iRkLM_e!6epzHLdlx@bw=5SPFCv`!q#@|8bX)3gd# z$3~BpxQ%Jez?vm4RipjoRe7xzZcg5$&2Q_pn)NJXv(bX~Hd7thZmm5=5JilARhuQ( zpLe9I^w==w3!rvcc&{(#8<%^Cpt^^{M+y zK>~YRg*k=y1$HS4#1w_2iV#qAGxbF_cUem*9bSRxakEq$B5Ya3wQx;`+(tns{hrje z2VzzgYxlYwN@rBo<3*g34-laqPkq{c79u&Bl#6F4Ga^mEdfH3f965>xcT@J}^j678 z(wwi(qercbZ*Rb6*+YCTuMwluVsamOXw1v50)~Xa)z#R?C3&2)YN=AbnqnQdQaW2w4<0kE zHc4h;JNyZ9V!oHv#S@#aRae|7G!R=A8u*5TM1*|ANvgrj&5lqm?Y!EpA>nWPRvIHL=Dxc(2@ekE8FpfulY;R%&xXz5RumtfO(sVDs(02d1lb z(KK{kQIH{7dYd~_(Bm;`l@v}QyExXEE9t#+62L8MI#jkt|Q z=tZ|Swxw#YSvgr=4zFtY{Nb7XBrZ)&nGx&LgQ`cw@x3O+aC39pEl+nPhdV}L#u{V9 zCPti%wICjRdj+aToxP34jYjKAXZmh$6>Ki|c#d~bZD0-J-N{)(jlutU93CU2!`f1i zJy*tlys{gEn+uNFtx~F|#Fu|aiBX_gH7wbjLfFWAsm*$qECp{v^tpOmhsNX!k0l$9 zb5UZIKAUSzR+3d1~`%664pCwTUt8ulw*1rU@VXyW z^YuMK7vsd{0?$;u$ZZm>#|1nRIqZ9aA7^!KhlKG-n^4>=BY=PHtKj|0vglzE9 z<@-NJcmNBn_lB#Qeh!tT-W#shonK(zBRVzmNQp-&kaa0=5vQe2*3QxQx|&9+7gV|+ z56wyz)LSK8V*jzR9;$>abRy2UAZmOdr$HF4xeAXt^DrM59uraz);*&A*J*Cy4 zU3PHrBu^}AnP0{9GenJ-JVqtL)&s#(TQ^HTVHh6O)g7XbK6@2oZmF@L^cw@Zgnxyyj>wzrnDK%sebmXy$?3#K(!uaE+w zy4p)4J9qow&qW86VVuP1oV}D6-7gt`u0qo{^2zqcH3bwyLb-sW?3@c)Chnmvp=BGQ$LxE>JJRMpR&@*tydcSk>{v{b_$P<#ND9tID zu5l|bF1phmW#>)u3+cIkG1H;9op)k#geI~vivNAIfc2H`0Doo(7&r9i;O2=%d|k%D zk~9z17Q3zOb6zxSn;uusQ|dF78#$YkdX-8Ptz={+7EQ4ev05|ZP^P%GHgjEk(!-%s zApLkvx3zeMh7_}LG>DB>jU|5FtVrU;Ap+i(hy;sAyc^v)olQUEQ$q;+%{{sL-jvLe zy)jLKPyOzY9Nv;io1mk+$2YRbA^^&i7{J7rANhgT>@}$vm=?dTdfLWF)~AV-_yUW@ z=qM>aLEkN}41+?4?wO8EgK;deU2oCLFk_yX`;`r+o$-FM7w12@{eGYsX;Y3fX}x&Z zXrv(${qA6=$YKM3ocpAZBG)({l~A8^SX%xczAU^W9j3?7*YP`1J%i3C1R~IKQi1ER zZj$Xqvtsv^er;7QmylQ;2~*qVouwqB!F8zE1V&%ZwTNm>D!$bk#?^KSR~5QexC-e) z@0BtZZG0>s#o#Q}z>&mmK5=Ri5rot~n|kYEyzf?5u<#H$$H{1TgICOW(p7x2*XO&v z*_5tClhV#Vf$@cQe%E(LEQJH%i1#H1ehZb7wla4!5?ROcrN~Uf;?^E^7krAQRw)&o z9gYGCXXoBuL#G>+7VtN#?oSyE(Z7Rba5kifwnm1gKJ1}zVpw-|(Lz%u`+ zYRNILkChH6ox>MfuKn(oZmp|^l|JPU=+C~kX!zrk%BdHq9{WO(VI?jhs}>f^GWW$X zL6=EwE!$(;U%-=H$~G>ahSJ-~BEvD^iG=5xUYYW#Xto zzD-1Kr$ptJ%Mp1Zv?;!Xe04IHj-YT_|HHx?KIS#TKwq-4P|v^Y^o&R*fSNH@5);mi zm`=dmpb)gW+kGW99r}c9ZMwztW4kTmz3qk{2)PCiqxUc=*vvmYqzQ37LoomTeF`mQ zw!--1*n14TrhW$uHKi31sM(S!o-kvPqO{%uWIw2U;QdGpq(Sazm3MqItk_~wo!n^qa!U(7O_o>+; zO|53S^VI?mZ(D@1tLA`G^hnh+`EJ}8PppWcZZP^xLuuW=huLfJtIi_8F2xx)vI987OZ0ZtA;c0JGN?uXX7uEln(`}}W-~u#kynDSTv=F}G zyVbpS7f&>8)JI@c)0PW*9K^Qm91Rh6v+&qFng5X84p&n1ro_Untp`K-hG;0c%uN8k z(rT}foKQbGzDyPFaEfexws@Rr{F~O}sSUsp-l{2;0GyS~h=d4@b6!d%8*36Yw;9{cI*8XsiRh7zsF zX6+&X*q~ASffV4e6m7h*z#>3Zw_7~0s%5v=LaIl^zUxxY7qq0w2tDaOpjD{~E!ZLk zrrVK2mut(_NHM6wtIB|GqNx6bmVEzbcp%ISCGycaIBZX%HBxZ!GATxIFigHJ!w@j) zh z;co934S5@s$vZ>7Ni7y=p=rFMB^IozHc@EGF32GJy(|b zgRpow7|QV)xCCuCVzN69u?r6yZ*D2iAq@(@MM(GzOZE$}5duZXwK-rlZ4-8K;*skX zXYvQsw|IwipM$)}wH?u{<@%TAntF8SZjF24;B&g3tZg&iw8=>18z20#Upk?I z%nG4Bc9G)RrNMwOol(u8HidB&A%D?zg6QObxExNCAshHu$S`S-snC;#_;1iX*rPS z5$ho%$nK2Ql?ag)KSo7=#uwu;qj_ZL#MsVGazb1Fxa{?3;$KTG!S z3B85B5pBxRHi5s6{E-F ztp+N}eOuSQPFyuAbybaiPfDH|zJ2**9RiL_|BwYCY~;_iAltv2{~DZN(rn8vU)C1`WSW~1 zELZ77!#`f)-=7kuAru{)_z$PHX(}Kkg4V4k@by{i!wXcDc)U|L+t?n@=6Nhlc3H&O zTR@hjs2OF(foJ^IL9m%OhTrMtS~TXx0QXVXo@Hcf;81M-&ZX792s+#hic#2HRXmWJ z`C9zfs!m(O0={UMN^kDIgY=pba4Vcc<>riISo$$`-miG>Z?Rd*5#aVbZ{Xk*du*SY z*GIb6um)Tzbm)5y>*G2S53zf;Cfs?stR@Cu^gZnlMt6)R2dWi1*advBw+`) z$nui~C9B3*;BhXzvKUx`sB)mFd#|5wGuo)kxLR+rb;W7C$)#><{ylTtTMBOL9<~ti zRxT+QhGarn^^dT_g3oSq|KKS*0Pg{5jxUb6wxR9! zxnwGfzwk~I6o<@W^KTA>wMz{L@lOL`qz39$1RShA;AhLrJ&x;^91l(v;b6i^?gL(n z4<0Z}_3vdriBO0_nyL`099O>WFJwNY1@&dR#$|F4YNunxebc0Cl&^`mZgmbV}Lwt z&onT2%wwdoxhHL@1>O%gWj`032NoYJGDfe3v|Sjfjc9iVUCD&PzG)IRI*i7efAfhpjZ+(+Xneou3!b#E`JElZQrgeax|u4Zb!8O|QFubl_lVjI zpih8QtE&#lf&rj3n~NEMz8zrl_{`b^uu|V;HNR0P3%?}iH+`M>7&qYz07Q(|V5;j( zH&9SV-0&z>kL|VhjBa^w<58bYTl#2&N!iVp2O1W#1yCajVuOCWR5qEpkfY3a=5c*G zH$*7o>C@K}F*T0L8LT0Ay71rT{8wJUy|?8`>VFi?EWX`3+$~#yz+iwg_)6mpkSZ^w;4?qf$4E`OtX0udDti&YIzDr-JX4Idu4|8C$~!d?&wR+VASG$9gT)_KRcl z!~m)0MA2+S<*f8tbb-rAEalilY{r=H2FQeqzA*_6xuFQ4BE=`K z)<`Ao#>fTHo9$t`nc#a+Z1d~Ku*pe)s0%|YPa<38F0+So1GwRFx%~>hwTMuu0pE>+ zAW{{^%aDL^N*Vb|rUi`BP?mprz0Y-XsUs!p3OLrBLkRs#;Ir(PCfn31WoMP%Qd4qW z>;(vOX10G-g^K$m;;X75s`g~^8sD!T1J9SvfpBy!#9#FwaH&cmKoOMuz{{{mgJ^OSs?|B{$@7Hi^y+Pf-=p ztWhs;(i3Pi{mV02Lb@sP@nX-57U%$|+-z?Woq8UW_Nlk31!D0`=hYC^^fHo*@{BIp zt>Q~_&wPA(6FU)@$TKDm5}wP>ZgXDgY5;W`w3Y!CT?MGOU`A@{^|3kdqOL$)p2)2J zo#k$*R626wHjIguAUnJ8DMgp z>aEq;q|KnC=j!n70S`oP=~Gc16K(-dHjFb_Dx1nGRgpRChCEtK%_v$F2B`io6J9@< zKq$?#&}VPSDbvn{lCbSN%=6rtbE~QaT!-D(#;W4fH2CL&rFMfD{Xs8y$FpL6?>!Nx zG2v%#DJbz6p_L5OKf#io%kHiR`3Q?Ep8YkwnDgY@~t14S$1)NPgg4f9YWw z@M!}#r>?0&0RN4l3((hZ)B13Am#lumA=#B)rw}}~syJmmG!mv>5T+(t+a$i&kYvs# zADp*~TDS@vxFxg_c(vvL|InomkcPmSbLM?__p{-NDHVNrgg=h2h7o9tYcoBCZX9vV zzT4{qf`BV~u8uwq(;O^5m6ip#Ss?`c;@oe98nphZVFW-LtqF8jbRj=HkCQjo)z%h9 zCyv%X78?ePB$r(^`VwGH`||6{>U7e}4xZBOY{e?at#Q*PtvNtrgnLB&yI-0v`FDKb zc-(|0B}k*Ci|W@_P9A>udoDuFU zMC@fuIXMIc2{t?aNGa(d&3k+Ih&CNMk%cjmPg_1rCP{u)7k(V?(6Wx*MuiV=I zqNCFJ`zUp^wJ+$I?)$Yn0eFNGkDi5M*>zIoRi^;AUVcZ>I{qV4#5 zOhVH_vV$9|8@b^0$8S6bbilA?{l;g5kX7(PuDv(L`&%KC$QthY-E*X)@Y#LXfkw06 zL_Q*zanbJIxG!iu-TzIBh=^!=yQSV#jELy?7yRkwnXXq1wbp-r^>=C0%T>I2UW|PNfBk*D zL_agmH*kXK-$VcPuuF${DG?^}Lcf@Sw4XGmDLuv6i~9*o@6RzJ$tY#(J3c)4)e~4~ zDd;ihRWt}M5yn896IZt^xHz-@HK(5*b(;i}NUKG+BZeI@fS&GX!*^5L5yOrc{_*=e z+OVSyJKFHCG-t;sc8p@jD0Ym3Q0cMb8+Lrdj&IoU4LiPJ2X@&(pLRgFKV!iT7Wo~A z-Vwu&7`~^6J7U-o!#`Q_jyCLQ!;Uumt7h6UiXEfaF^V0dAOs}*|K%IX0`0N;XENUA RKobm+;zhL!S?5jt{}1Fk@=gE% literal 0 HcmV?d00001 diff --git a/dev_docs/shared_ux/browser_snapshots_filter2.png b/dev_docs/shared_ux/browser_snapshots_filter2.png new file mode 100644 index 0000000000000000000000000000000000000000..4eb960ca3b0eda049dfe425d7e27cd22ca880789 GIT binary patch literal 75522 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 Lc^3ZRz`4HxtuJ+j literal 0 HcmV?d00001 diff --git a/dev_docs/shared_ux/browser_snapshots_listing.png b/dev_docs/shared_ux/browser_snapshots_listing.png new file mode 100644 index 0000000000000000000000000000000000000000..076946c09740388cb5c8c0741261c7de680e0f97 GIT binary patch literal 181608 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 z z6T4D-W&--v@T%+;(VJ^Q>Dkzz#I3PG<6I>*oh7&vf~sYa+w7=+T-B1ZK~mY z4)nH80>Tp4G=gR!nz@MC+;`O{@=_(Z?>ny7`LJUxSs(>Z%s0>~XjCK^DQ@j;laW~^ z3o75Wko5J!s>`9$ibO-Z`6E+OkS0xmi_T9HPv=0F^H72tKtGR}CA`|LkSC~?$$t+c z(w*LeCa*MAlCyV|)Pro`!rC4EX7LGm>-H^K=YXyE(h=<43F@dci510p_2vyh99i0< z{J3c=0kqOEw=iS5-qK&)4dZSn_c5^!clh!#*5FfLygn9}GlrDv_uaO9wQ!JJ%-a&t z0s5u9R9=Yx&IoJut|065`dIWN7S?k8JhzwF zCli-q?SjGMsG2 zWnQ7Me`jU-hHtr(GyX$mGE|Vm2$VYv9O3QD5YOq_tfwAs@mxI!Un|a#o$=wu<$D~N zA%^9p4fhe})|iJ8T#&Jf-GfHTT+f5{PU_|b{~;H#>J;^P!1U3honiroOi|Po+2k>-77dOqK$L3Ke_+m-6wzkJD~&v zde2-c4omg-z?@d0T+VRFgxBri9-q)?x!{ve|4>6Un=2azjlW?ymu^1Vbb?Gc&f} zbKO!OHQeSn*WxY{;VUzPQkp(dFo6Vqcen7q(q6hlla98I&ehElqxysMJFVMu?jj1 zDK&oN|M0TvodJ#>28(XNQ(A`1jEQrUDe9fJJ8zxBu7jF|Ije?2LQk~KiqaNNi~GC) z4v^pzG(>r|y(;Te+u**SEL|ETKz6kLwDI{o3QNtUPvlw6>KLDxa2SWDO?s5(i?9a$ zD2MON;XD(#eWPVYy9#Rn-T4@{zVo3>^Q2BW7LCN=K%xPGhJx2HtBjPKt)jy1TOJc^ zK6ok}AwN+lEiS7#efs!d7sPwKUZOCYn^X4^W$lJl0TySGp5fJbb3T3ShC1S#57=U+ z0c9e+h|E3*bEhf6@szG|Z;1aVZFbYN?}P`gO$-XFvRen1q~MGMfuFiRCoc;(A2Sji z?`*Isu=)qdbbf3eXxus{OK)UXR1fIRG5dQyPB4Hj>i6wLQ;sp7Wgh zzPaD`{quL7f4KD8^o^#_^i<+hdZ0Cp!8g<2q zqxm)&PBsFJT}llNvovl1Z-;%n7jT^rEYVy0?WGIsEdj>TXV5J3c?0)*G$j@4kV8};%;+hNgUt|9Xt(0pH@{ae0Z}}X} zT8wJfY3JUCDwxcXACOq@-^x;Rq3fzJY%eG6|0Vmw6IZ{;myDs|0h;i@kwk+@Emd?A zn??vZH#!;g9nTt~sZj-xpIM&}RoxXkuy(}Hpw?4$IYhv{&`_ysI`heU^9-|=2=mI>Ru^UC`n8B8 zn8*3)lQp<(Xvo$qi)!X@H(|ukO2vcru?)?^ZUC*XrtFRD2^o^MiyWrxMFqs1(y)n6 z%j`UUes&E0z7r@eB<;8N+N3;7U(0tMb1mm+gH1n=o`WL}+7f9$n!lAqeo)t=pIu79 zh(?kpO~1!qsya5AtXco~cPFX)=5>?I(X4t#{q39eQKp0?9Hb!k~6?&8nI<ⅇ9 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
EgJZQ-^KC$%hU`Ez(*Ppo=7T zG=f792hD|y*crbr^}miisGmZe$qta<6LKk0Qb7IIH3BXdTc4ak@+OqWULdgFV(6?= z?PtU9eFo@*x#M*!X{O|~Jbv^Xd45v^t~iD!xhT-f!%7pZ;lH2Y+!&|;73iiy9Mud=PM>**ct2IK7XB^pqraxjq4zm1$iH@GUzrMG7A}5Coo|wbo4Zt7 z6xRezNHX1w7Vb!+S?x`@p*tq+soQyvmRAQ6$dtGYGCqTWZQ>Rs?tLsTQ4Ay5jDX(` zN7w}l$yFhYxaLgv2iP4&HM1tlQQ3cp;QDy6ZfJvPPp4)7V5q& zw!J>hk3B`AI1;s*8$JITm7?G`zaMSew22}Uz-;pJ8bGp=F-$jk*sdmI?)}l5wi?^$ z;4^2=gzv6&ZlP6Q=SHa{(J3!o7(Of82}B{3@KrQo5XHgwNT+8 z!=EX;@N{z57^R&gx?x6T_5`BK*va;QX-)(C~pQlSA0}uVlsUXoNtcGE&W@ zbpW9=J@e}jYnTi0Pvugaw4LRAdK`6~gE3%?inIerHsmv*7YwEW?JYl~J;1+%e4h2m zs)LR<=TVXhos&`zT6Frry8LaYDZI*WySbbd22YN9F$}N)CX3~;pnyE3-LY)+K&*$) z>+9ODO?Qy@(B&PcOk|Un03_0W%)@~Ed4UL5CW63gj;Ee!zvwi5|CI+BkZ4C$$g)s{ zb83x=$fk8c%=+H+xLOQSh{79^krg|B>J;CHCEOwxzIBR`yjeT}IuYJeX8=Yq0n7=W0UJE6&F^m*;!)tT%>;)xE%nbUCb;f3Fp|bcy#e0M%*En3;J2w*t9*|vZYJMz!TOs%ff4gxlQcZE3OR= z`GK=hobtH9kHt58?c2}hG`5zzAFhj>Wvy=9_^5~;C=-xtdOWi6k$#+5)sF`7@Oe%98gGaHQ<93KN&sgI%T zIPf%yH>{o)DQute+HmA(DUYEl`uYl1bQaJ`s<+2=w-nq~-vND{xUtuq5nnLRvyo*4?KWQVOvVaiS^bB&TbNr|$HB8s7||s=l)wCpbUPCEdc)K8PM3?V zAlra!%gG$yTD`8HaIoSaMI@_~??NdstgFzv^7sI&atDJ>%vNQPoMjdfYSA~_D#-yYf-=m6fmf8~HA zC=e9wdPHc)#BcItS9=Uq#2qh)q8#{>tz^B`Q zjA_n~V{pW#4IhF?BT}WP-qlOD2ST+RF7UnQ&9|d3q}&}xUDyQW{%5HFZE`8n8*ky$ zv(FS-EukYgl@OroQH<6d4Z%ByMmi4Rq{QS^Ujnm9dYnLgw!>+zFCtl%w zjxfRx`VCrD=fd*UY`;V=E2%Xni> zC4(q$@m9g+SLGafL&+fs?e-pPo)+okagR*w zT?vo!E!NeOUx~gcy(*yB+C2kiEzGModCOY#{czu7aWWBl4|ca#uA>4gtZnVh_hj#% z7s?B}-mIFyb6~xmLV-4-v%IYRjQcB@paI|N_S!beK_y64X4pM-q?29KuM|1CDVI0I zQ7UqQ=InAtfCkrRQeS*}ze>vY;WDi2SRjMt$1ud~2XKLAh)u)E@Z45`Udw^{$k3?G z9RCJkP+$3Spv5Xsh~dl;9%3_B;0wNAL z;+c}I-~?6X9u?)l5w_o?>-q8qgD>{tzpq zJj}9>wLZB42A0Cd+aaOI>yK!cWY|hdhC6+#&Tn8W^FVGcB=O5v(EH}b=}AYn8Oslu zXZa<%rs=R-Bb3+M%|3$fUbA4rKcwjzpsvPqwU6iz$mkW+&hcPcIc;M`KWuF*NP@TG zR{3Mo67Pt8ZWW0|A<0F2uWGg@W`K+LMyDE_-wT79m!8bs6nnBhK{C94EUZs=DiJlqv z`FHnkYBlm^UP)9l9xPAI;9%)V7?JL9{>Hl9uiD|N)bZBpZv2#;Vf^zMcH*69!B{ApNz#Xb9j}>v5Aj&7i6muw?oZA)BtX9j zq6S;m4GH@w^kYfz9po%gqaQ$2AYa3w%E#JxN6I0=o;MV`*PeFdDz?GN=f(dSQ6VOF zQW16~-c0_%q50QNa+MK|18o1?CHP2;0$!U3lPKtWAI+2JZ`cGFHYt*VHK9#F;6P7^+p6acC%wzaiPv^zLr?ZkZPaY z+Ny8(F__dp{}-E_CJiNFmvPYrcsfIy?~DJ2?3_lFRPOE;jUS}~e~zk)vL^MdUYG!6 z3wSV}NxbT%!PEdLg&U89hhw~Vfd>QY&A`Y?xz!mzxW~%FeesG zJ&%l_ixG{Pxy5XEOEIq6_UES}-U7bHCfw)y!{vb+s&2`s#t?no5W~+S^8q!C=cV&r zWOPd?6!wr8IqS!i(Yef@kLK!8@Qb$K=AeR?bXABK*L_5^#v~NwU;T^8E+LzDu3YTb zL&mF&On^<(ncBT!j|6|1b$y>|4`y&o&S*jA3_VRnNeF&JE%An{X+Zq1@cO~jsoeo< z-V&vQ$avKbtBn>GSm3VBQx5wfkNShpBV)87A8hfOs7OP8jvylw;;M}MfBkA0OMW&} zf6tLGFrYE|0mA$K!DrE!*E@a@8UOkfvM!jioPHkO|9pwBx1b;I%l|H9{N93o kZ$Uqfk^iS>H-39ZCqq8{@z6iIN#LKpHdd=t<5=8(0mRFd+W-In literal 0 HcmV?d00001 diff --git a/dev_docs/shared_ux/chromium_version_command.png b/dev_docs/shared_ux/chromium_version_command.png new file mode 100644 index 0000000000000000000000000000000000000000..eb1fc2f7aa050917e7dd23f4c250a5604e05ebe0 GIT binary patch literal 140479 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. + +- We'd then want to copy the checksum value of this file and update the current value of `archiveChecksum`, next we extract the content of this archive, so we might also compute the value of `binaryChecksum` to determine the correct path for the platform; we check the value of `binaryRelativePath` knowing this value we run the sha256sum util against this path and update the current value with the one received from the computation. + + We repeat the same process for Windows. + +### **2.2 Providing chromium version for Linux** + +Given that chromium is typically operated with a GUI and our assumption is that folks that are installing kibana on linux machines are doing so on their servers, hence the variant of chromium that kibana uses on linux machines is slightly different in that by default they are able to run without a GUI for this reason we build our own variant. + +However because the chromium codebase is large to say the least, we build the headless chrome on a VM, for the next steps, you'll need to have access to the "elastic-kibana" project on google console. Also have `gcloud` cli tool installed. (You can install this pretty quickly using [brew](https://formulae.brew.sh/cask/google-cloud-sdk), alternatively if you'd rather install from source because reasons, you'd want to [see here](https://cloud.google.com/sdk/docs/install)) + + A VM template has been created that fulfills all the compute, network and build requirements so that the build process is sped up as much as possible; + +- On GCP, opt to create a VM from an instance template, the template you should select would be the **"rd-build-chromium-linux"** template. On creating this VM, you'd want to take a look at the README file for building chromium **[here](https://github.com/elastic/kibana/tree/main/x-pack/build_chromium)**. +- Next you'd want to connect to the VM using the gcloud tool we'd initially installed, you can grab the command for your own particular VM by selecting the VM and clicking the SSH option, when you select the view gcloud command. The value displayed to you should be something along the lines of; + + ``` + gcloud compute ssh --zone "us-central1-a" "rd-eokoneyo-build-chromium-linux" --project "elastic-kibana-184716" --ssh-key-file ~/.ssh/id_ed25519 + ``` + + Depending on the setup you have you might not need to pass your SSH key, but if it's slightly different you might need to pass a key that's identifiable by google using the **"--ssh-key-file"** option. + +- From here on simply run through the steps outlined in the readme. + +- If it happens that on completing the build your user doesn't have permissions within the VM to upload the build artifacts to the dedicated storage. This is fine, we'll deal with that later. +- Next we need to extract said artifact from your VM so we can compute the checksums for the archive and the binary we just built. + +- To get the build artifact out of the VM, you'd want to leverage the **scp** functionality provided by gcloud cli; We do this by running a command similar to the one below again only providing the ssh key if it is required to identify yourself, we should replace the host name with the name of your VM and the path to the zip file with the correct path on your vm; + + ``` + gcloud compute scp --zone "us-central1-a" --project "elastic-kibana-184716" --ssh-key-file ~/.ssh/id_ed25519 rd-eokoneyo-build-chromium-linux:/home/eyo.eyo/chromium/chromium/src/out/headless/chromium-fe621c5-locales-linux_x64.zip . + ``` + + Preferably run this command in the same directory we'd created to contain all our build artifacts. This command assumes we just built the linux x64 variant, there will be two files created: a **.zip** and a **.sha256** file (this is useful to verify that the file we download from the build is not corrupted). We'd want to run a similar command to download the .sha256 file too. + + We should perform this step before building another variant (i.e. the arm64) because artifacts from the previous build gets cleaned out. + +- On downloading both the .zip and .sha256 file to our machine, we attempt to calculate the checksum of the just downloaded archive; it should equal the value of the contents of the .sha256 file. Assuming all is well we would repeat the same process we did undertake for the mac and windows platform updating path.ts with the checksum value. In every update the value of revision for linux is always the version our script provided. + +- Assuming we've completed this step for both variants we currently build for; we might then choose to upload the archives and their respective .sha256 files to the storage buckets so they can be accessed publicly, leveraging gcloud cli this time with the gsutil command that comes bundled with gcloud; + + Running the following command; + + ``` + gsutil cp ./chromium-fe621c5-locales-linux_* gs://headless_shell_staging + ``` + + and + + ``` + gsutil cp ./chromium-fe621c5-locales-linux_* gs://headless_shell + ``` + + Would copy the files to both the staging and production buckets. + +If you've made it all the way through, all that's left is testing everything works as it should. + +## 3. Testing + +### **3.1 Locally** + +The first step of verification is to start kibana, locally. On whatever machine you use kibana should be able to download the new version of chromium from the updated path.ts file, it might help to add the following to your kibana.yml; + +``` + logging.loggers: + - name: plugins.reporting + level: debug + - name: plugins.screenshotting + level: debug +``` +so we can verify that on requesting report generation the chromium version being used is indeed the one we just provided; + +### **3.2 Docker** + +This step is required to validate our linux builds, especially considering that we are mostly developing with machines that have a GUI, For this step you want to follow the instructions outlined in an example puppeteer update PR [https://github.com/elastic/kibana/pull/192345](https://github.com/elastic/kibana/pull/192345) + +### 3.3 **CI** + +CI also runs against the build too pulling the assets we upload to the buckets, to run integration test. diff --git a/x-pack/build_chromium/README.md b/x-pack/build_chromium/README.md index 5f9e2bb06317d..15d335077f7f0 100644 --- a/x-pack/build_chromium/README.md +++ b/x-pack/build_chromium/README.md @@ -83,22 +83,6 @@ settings, including the defaults. Some build flags are documented **NOTE:** Please, make sure you consult @elastic/kibana-security before you change, remove or add any of the build flags. -## Directions for Elasticians - -If you wish to use a remote VM to build, you'll need access to our GCP account. - -**NOTE:** The builds should be done in Ubuntu on x64 architecture. ARM builds -are created in x64 using cross-compiling. CentOS is not supported for building Chromium. - -1. Login to Google Cloud Console -2. Click the "Compute Engine" tab. -3. Create a Linux VM: - - 8 CPU - - 30GB memory - - 80GB free space on disk (Try `ncdu /home` to see where space is used.) - - "Cloud API access scopes": must have **read / write** scope for the Storage API. Access scopes in the GCP VM instance needs to be set to allow full access to all Cloud APIs vs default access (this will return a 403 otherwise in the build.py script) -4. Install [Google Cloud SDK](https://cloud.google.com/sdk) locally to ssh into the GCP instance - ## Artifacts After the build completes, there will be a .zip file and a .md5 file in `~/chromium/chromium/src/out/headless`. These are named like so: `chromium-{first_7_of_SHA}-{platform}-{arch}`, for example: `chromium-4747cc2-linux-x64`. From 6393bf8511460a79fa40be6c831f3032c407861b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Wed, 16 Oct 2024 16:54:28 +0100 Subject: [PATCH 17/30] [ECO] Dashboards do not link on EEM Service View (#196345) closes https://github.com/elastic/kibana/issues/194042 https://github.com/user-attachments/assets/f0d83363-f1f4-4d8f-be7a-db73ed084d43 --- .../public/components/app/service_dashboards/index.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_dashboards/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_dashboards/index.tsx index 627c314bf72e6..a92d781e3dd7c 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_dashboards/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_dashboards/index.tsx @@ -40,12 +40,14 @@ import { useDashboardFetcher } from '../../../hooks/use_dashboards_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; import { APM_APP_LOCATOR_ID } from '../../../locator/service_detail_locator'; import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; +import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; +import { isLogsOnlySignal } from '../../../utils/get_signal_type'; export interface MergedServiceDashboard extends SavedApmCustomDashboard { title: string; } -export function ServiceDashboards({ checkForEntities = false }: { checkForEntities?: boolean }) { +export function ServiceDashboards() { const { path: { serviceName }, query: { environment, kuery, rangeFrom, rangeTo, dashboardId }, @@ -53,6 +55,10 @@ export function ServiceDashboards({ checkForEntities = false }: { checkForEntiti '/services/{serviceName}/dashboards', '/mobile-services/{serviceName}/dashboards' ); + const { serviceEntitySummary, serviceEntitySummaryStatus } = useApmServiceContext(); + const checkForEntities = serviceEntitySummary?.dataStreamTypes + ? isLogsOnlySignal(serviceEntitySummary.dataStreamTypes) + : false; const [dashboard, setDashboard] = useState(); const [serviceDashboards, setServiceDashboards] = useState([]); const [currentDashboard, setCurrentDashboard] = useState(); @@ -150,7 +156,7 @@ export function ServiceDashboards({ checkForEntities = false }: { checkForEntiti return ( - {status === FETCH_STATUS.LOADING ? ( + {status === FETCH_STATUS.LOADING || serviceEntitySummaryStatus === FETCH_STATUS.LOADING ? ( } title={ From f8d2fff447c04089e24d2b22c05528594b88af13 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Wed, 16 Oct 2024 11:58:49 -0400 Subject: [PATCH 18/30] [Canvas] Use core http method to access internal API (#195790) --- x-pack/plugins/canvas/public/application.tsx | 2 +- x-pack/plugins/canvas/public/functions/index.ts | 2 +- x-pack/plugins/canvas/public/functions/timelion.ts | 9 +++------ 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/canvas/public/application.tsx b/x-pack/plugins/canvas/public/application.tsx index 222b64e4175e9..92ae3ebb6a00e 100644 --- a/x-pack/plugins/canvas/public/application.tsx +++ b/x-pack/plugins/canvas/public/application.tsx @@ -95,8 +95,8 @@ export const initializeCanvas = async ( // Some of these functions have deep dependencies into Canvas, which was bulking up the size // of our bundle entry point. Moving them here pushes that load to when canvas is actually loaded. const canvasFunctions = initFunctions({ + http: coreSetup.http, timefilter: setupPlugins.data.query.timefilter.timefilter, - prependBasePath: coreStart.http.basePath.prepend, types: setupPlugins.expressions.getTypes(), paletteService: await setupPlugins.charts.palettes.getPalettes(), }); diff --git a/x-pack/plugins/canvas/public/functions/index.ts b/x-pack/plugins/canvas/public/functions/index.ts index ad91d6b98fa7f..15985b0fa7628 100644 --- a/x-pack/plugins/canvas/public/functions/index.ts +++ b/x-pack/plugins/canvas/public/functions/index.ts @@ -15,7 +15,7 @@ import { plotFunctionFactory } from './plot'; import { pieFunctionFactory } from './pie'; export interface InitializeArguments { - prependBasePath: CoreSetup['http']['basePath']['prepend']; + http: CoreSetup['http']; paletteService: PaletteRegistry; types: ReturnType; timefilter: CanvasSetupDeps['data']['query']['timefilter']['timefilter']; diff --git a/x-pack/plugins/canvas/public/functions/timelion.ts b/x-pack/plugins/canvas/public/functions/timelion.ts index 7ab272911389d..8f2e2c6562bc0 100644 --- a/x-pack/plugins/canvas/public/functions/timelion.ts +++ b/x-pack/plugins/canvas/public/functions/timelion.ts @@ -11,7 +11,6 @@ import { i18n } from '@kbn/i18n'; import type { TimeRange } from '@kbn/es-query'; import { ExpressionFunctionDefinition, DatatableRow } from '@kbn/expressions-plugin/public'; -import { fetch } from '../../common/lib/fetch'; // @ts-expect-error untyped local import { buildBoolArray } from '../../common/lib/build_bool_array'; import { Datatable, ExpressionValueFilter } from '../../types'; @@ -132,16 +131,14 @@ export function timelionFunctionFactory(initialize: InitializeArguments): () => let result: any; try { - result = await fetch(initialize.prependBasePath(`/internal/timelion/run`), { - method: 'POST', - responseType: 'json', - data: body, + result = await initialize.http.post(`/internal/timelion/run`, { + body: JSON.stringify(body), }); } catch (e) { throw errors.timelionError(); } - const seriesList = result.data.sheet[0].list; + const seriesList = result.sheet[0].list; const rows = flatten( seriesList.map((series: { data: any[]; label: string }) => series.data.map((row) => ({ From 40f95132e8032787b995bd68d8f265fffea2760e Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Wed, 16 Oct 2024 18:01:48 +0200 Subject: [PATCH 19/30] [ES|QL] Fixes inline casting wrong validation (#196489) --- .../kbn-esql-validation-autocomplete/src/shared/helpers.ts | 4 ++-- .../src/validation/esql_validation_meta_tests.json | 5 +++++ .../src/validation/validation.test.ts | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts index ce9cec58575fc..e3e3da4277344 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts @@ -46,7 +46,7 @@ import { } from '../definitions/types'; import type { ESQLRealField, ESQLVariable, ReferenceMaps } from '../validation/types'; import { removeMarkerArgFromArgsList } from './context'; -import { isNumericDecimalType } from './esql_types'; +import { compareTypesWithLiterals, isNumericDecimalType } from './esql_types'; import type { ReasonTypes } from './types'; import { DOUBLE_TICKS_REGEX, EDITOR_MARKER, SINGLE_BACKTICK } from './constants'; import type { EditorContext } from '../autocomplete/types'; @@ -473,7 +473,7 @@ export function checkFunctionArgMatchesDefinition( const lowerArgType = argType?.toLowerCase(); const lowerArgCastType = arg.castType?.toLowerCase(); return ( - lowerArgType === lowerArgCastType || + compareTypesWithLiterals(lowerArgCastType, lowerArgType) || // for valid shorthand casts like 321.12::int or "false"::bool (['int', 'bool'].includes(lowerArgCastType) && argType.startsWith(lowerArgCastType)) ); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json b/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json index 736159b36384d..a646c0323a76f 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json +++ b/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json @@ -9546,6 +9546,11 @@ "error": [], "warning": [] }, + { + "query": "from a_index | where 1::string==\"keyword\"", + "error": [], + "warning": [] + }, { "query": "from a_index | eval trim(\"23\"::double)", "error": [ diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts index 66de6c7fc70ad..dd04f0e506fe8 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts @@ -1636,6 +1636,8 @@ describe('validation logic', () => { // accepts casting with multiple types testErrorsAndWarnings('from a_index | eval 1::keyword::long::double', []); + testErrorsAndWarnings('from a_index | where 1::string=="keyword"', []); + // takes into account casting in function arguments testErrorsAndWarnings('from a_index | eval trim("23"::double)', [ 'Argument of [trim] must be [keyword], found value ["23"::double] type [double]', From 231b240d090a8437e9834c1a2351223c7fb38e45 Mon Sep 17 00:00:00 2001 From: Robert Oskamp Date: Wed, 16 Oct 2024 18:02:41 +0200 Subject: [PATCH 20/30] Revert "[SKIP ON MKI][DA] Deployment Agnostic api integration `burn_rate_rule.ts` (#196259)" (#196533) This reverts commit 2c876e8010ce2785c784879217ee2a47cb48e7b0. ### Details The setting that made these tests fail has been reverted from the QA environment for now. --- .../apis/observability/alerting/burn_rate_rule.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/burn_rate_rule.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/burn_rate_rule.ts index 250fdb07b7132..e556db2e09a28 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/burn_rate_rule.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/burn_rate_rule.ts @@ -23,9 +23,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const isServerless = config.get('serverless'); const expectedConsumer = isServerless ? 'observability' : 'slo'; - describe('Burn rate rule', function () { - // see details: https://github.com/elastic/kibana/issues/196252 - this.tags(['failsOnMKI']); + describe('Burn rate rule', () => { const RULE_TYPE_ID = 'slo.rules.burnRate'; const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; const RULE_ALERT_INDEX = '.alerts-observability.slo.alerts-default'; From 8bd567b73a1b4385cfcfac26f7d18142a3b76a5d Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Wed, 16 Oct 2024 18:14:04 +0200 Subject: [PATCH 21/30] [ML] E5 discplaimer in the flyout (#196347) ## Summary Adds E5 disclaimer to the "Add model" flyout. image --- .../ml/public/application/model_management/add_model_flyout.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/ml/public/application/model_management/add_model_flyout.tsx b/x-pack/plugins/ml/public/application/model_management/add_model_flyout.tsx index 563797b2ae932..5a92a67962579 100644 --- a/x-pack/plugins/ml/public/application/model_management/add_model_flyout.tsx +++ b/x-pack/plugins/ml/public/application/model_management/add_model_flyout.tsx @@ -222,6 +222,7 @@ const ClickToDownloadTabContent: FC = ({ id="xpack.ml.trainedModels.addModelFlyout.e5Description" defaultMessage="E5 is a third party NLP model that enables you to perform multi-lingual semantic search by using dense vector representations. This model performs best for non-English language documents and queries." /> +  {models[0].disclaimer}

From 4605cc03074aad77dba7b7ceadd691fc80f9cc58 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Wed, 16 Oct 2024 12:21:48 -0400 Subject: [PATCH 22/30] [Synthetics] Test `useMonitorStatusData` hook (#195438) ## Summary Recently we had some issues related to module-level logic errors in a fairly complicated hook. This PR adds a new jest suite for the hook in question that covers some baseline usage. It could be improved in the future with additional test cases. --- .../use_monitor_status_data.test.ts | 356 ++++++++++++++++++ .../monitor_status/use_monitor_status_data.ts | 43 ++- 2 files changed, 387 insertions(+), 12 deletions(-) create mode 100644 x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/use_monitor_status_data.test.ts diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/use_monitor_status_data.test.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/use_monitor_status_data.test.ts new file mode 100644 index 0000000000000..44dd45991471f --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/use_monitor_status_data.test.ts @@ -0,0 +1,356 @@ +/* + * 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 { renderHook, act } from '@testing-library/react-hooks'; +import * as reactRedux from 'react-redux'; +import { useBins, useMonitorStatusData } from './use_monitor_status_data'; +import { WrappedHelper } from '../../../utils/testing'; +import * as selectedMonitorHook from '../hooks/use_selected_monitor'; +import * as selectedLocationHook from '../hooks/use_selected_location'; +import { omit } from 'lodash'; + +describe('useMonitorStatusData', () => { + let dispatchMock: jest.Mock; + beforeEach(() => { + dispatchMock = jest.fn(); + jest.spyOn(reactRedux, 'useDispatch').mockReturnValue(dispatchMock); + jest.spyOn(selectedLocationHook, 'useSelectedLocation').mockReturnValue({ + id: 'us-east-1', + label: 'us-east-1', + isServiceManaged: true, + }); + jest.spyOn(selectedMonitorHook, 'useSelectedMonitor').mockReturnValue({ + monitor: { + id: 'testMonitorId', + type: 'browser', + name: 'testMonitor', + enabled: true, + schedule: { + number: 5, + unit: 'm', + }, + locations: ['us-east-1'], + tags: [], + apiKey: '1234', + config: { + synthetics: { + type: 'simple', + timeout: 10, + frequency: 5, + url: 'http://elastic.co', + method: 'GET', + request: { + headers: {}, + }, + response: { + status: 200, + }, + }, + }, + }, + } as any); + }); + afterEach(() => { + jest.clearAllMocks(); + }); + + it('does not request status data when interval is invalid', async () => { + const props = { + from: 1728310613654, + to: 1728311513654, + initialSizeRef: { current: { clientWidth: 0 } as any }, + }; + const { result } = renderHook(() => useMonitorStatusData(props), { + wrapper: WrappedHelper, + }); + expect(result.current).toBeDefined(); + expect(result.current.minsPerBin).toBeNull(); + expect( + dispatchMock.mock.calls.some((args) => args[0].type === 'QUIET GET MONITOR STATUS HEATMAP') + ).not.toBe(true); + }); + + it('handles resize events and requests based on new data', async () => { + const props = { + from: 1728310613654, + to: 1728317313654, + initialSizeRef: { current: { clientWidth: 0 } as any }, + }; + const { result } = renderHook(() => useMonitorStatusData(props), { + wrapper: WrappedHelper, + }); + await act(async () => { + result.current.handleResize({ width: 250, height: 800 }); + // this is necessary for debounce to complete + await new Promise((r) => setTimeout(r, 510)); + }); + const fetchActions = dispatchMock.mock.calls.filter( + (args) => args[0].type === 'QUIET GET MONITOR STATUS HEATMAP' + ); + expect(fetchActions).toHaveLength(1); + expect(omit(fetchActions[0][0], 'meta')).toMatchInlineSnapshot(` + Object { + "payload": Object { + "from": 1728310613654, + "interval": 7, + "location": "us-east-1", + "monitorId": "testMonitorId", + "to": 1728317313654, + }, + "type": "QUIET GET MONITOR STATUS HEATMAP", + } + `); + }); +}); + +describe('useBins', () => { + it('generates bins and overlays histogram data', () => { + const { result } = renderHook( + () => + useBins({ + minsPerBin: 5, + fromMillis: 1728310613654, + toMillis: 1728313563654, + dateHistogram: [ + { + key: 1728310613654, + key_as_string: '2023-06-06T00:56:53.654Z', + doc_count: 1, + down: { + value: 0, + }, + up: { + value: 1, + }, + }, + { + key: 1728310613654 + 300000, + key_as_string: '2023-06-06T00:56:53.654Z', + doc_count: 1, + down: { + value: 0, + }, + up: { + value: 1, + }, + }, + { + key: 1728310613654 + 600000, + key_as_string: '2023-06-06T00:56:53.654Z', + doc_count: 1, + down: { + value: 1, + }, + up: { + value: 0, + }, + }, + { + key: 1728310613654 + 900000, + key_as_string: '2023-06-06T00:56:53.654Z', + doc_count: 1, + down: { + value: 2, + }, + up: { + value: 1, + }, + }, + ], + }), + { wrapper: WrappedHelper } + ); + expect(result.current).toMatchInlineSnapshot(` + Object { + "timeBinMap": Map { + 1728310800000 => Object { + "downs": 0, + "end": 1728310800000, + "start": 1728310500000, + "ups": 1, + "value": 1, + }, + 1728311100000 => Object { + "downs": 0, + "end": 1728311100000, + "start": 1728310800000, + "ups": 1, + "value": 1, + }, + 1728311400000 => Object { + "downs": 1, + "end": 1728311400000, + "start": 1728311100000, + "ups": 0, + "value": -1, + }, + 1728311700000 => Object { + "downs": 2, + "end": 1728311700000, + "start": 1728311400000, + "ups": 1, + "value": -0.3333333333333333, + }, + 1728312000000 => Object { + "downs": 0, + "end": 1728312000000, + "start": 1728311700000, + "ups": 0, + "value": 0, + }, + 1728312300000 => Object { + "downs": 0, + "end": 1728312300000, + "start": 1728312000000, + "ups": 0, + "value": 0, + }, + 1728312600000 => Object { + "downs": 0, + "end": 1728312600000, + "start": 1728312300000, + "ups": 0, + "value": 0, + }, + 1728312900000 => Object { + "downs": 0, + "end": 1728312900000, + "start": 1728312600000, + "ups": 0, + "value": 0, + }, + 1728313200000 => Object { + "downs": 0, + "end": 1728313200000, + "start": 1728312900000, + "ups": 0, + "value": 0, + }, + 1728313500000 => Object { + "downs": 0, + "end": 1728313500000, + "start": 1728313200000, + "ups": 0, + "value": 0, + }, + 1728313800000 => Object { + "downs": 0, + "end": 1728313800000, + "start": 1728313500000, + "ups": 0, + "value": 0, + }, + }, + "timeBins": Array [ + Object { + "downs": 0, + "end": 1728310800000, + "start": 1728310500000, + "ups": 1, + "value": 1, + }, + Object { + "downs": 0, + "end": 1728311100000, + "start": 1728310800000, + "ups": 1, + "value": 1, + }, + Object { + "downs": 1, + "end": 1728311400000, + "start": 1728311100000, + "ups": 0, + "value": -1, + }, + Object { + "downs": 2, + "end": 1728311700000, + "start": 1728311400000, + "ups": 1, + "value": -0.3333333333333333, + }, + Object { + "downs": 0, + "end": 1728312000000, + "start": 1728311700000, + "ups": 0, + "value": 0, + }, + Object { + "downs": 0, + "end": 1728312300000, + "start": 1728312000000, + "ups": 0, + "value": 0, + }, + Object { + "downs": 0, + "end": 1728312600000, + "start": 1728312300000, + "ups": 0, + "value": 0, + }, + Object { + "downs": 0, + "end": 1728312900000, + "start": 1728312600000, + "ups": 0, + "value": 0, + }, + Object { + "downs": 0, + "end": 1728313200000, + "start": 1728312900000, + "ups": 0, + "value": 0, + }, + Object { + "downs": 0, + "end": 1728313500000, + "start": 1728313200000, + "ups": 0, + "value": 0, + }, + Object { + "downs": 0, + "end": 1728313800000, + "start": 1728313500000, + "ups": 0, + "value": 0, + }, + ], + "xDomain": Object { + "max": 1728313800000, + "min": 1728310800000, + }, + } + `); + }); + + it('returns a default value if interval is not valid', () => { + const { result } = renderHook( + () => + useBins({ + minsPerBin: null, + fromMillis: 1728310613654, + toMillis: 1728313563654, + }), + { wrapper: WrappedHelper } + ); + expect(result.current).toMatchInlineSnapshot(` + Object { + "timeBinMap": Map {}, + "timeBins": Array [], + "xDomain": Object { + "max": 1728313563654, + "min": 1728310613654, + }, + } + `); + }); +}); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/use_monitor_status_data.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/use_monitor_status_data.ts index 710ff65de7c66..160287f9a3683 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/use_monitor_status_data.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/use_monitor_status_data.ts @@ -28,6 +28,7 @@ import { quietGetMonitorStatusHeatmapAction, selectHeatmap, } from '../../../state/status_heatmap'; +import type { MonitorStatusHeatmapBucket } from '../../../../../../common/runtime_types'; type Props = Pick & { initialSizeRef?: React.MutableRefObject; @@ -99,7 +100,36 @@ export const useMonitorStatusData = ({ from, to, initialSizeRef }: Props) => { [binsAvailableByWidth] ); - const { timeBins, timeBinMap, xDomain } = useMemo((): { + const { timeBins, timeBinMap, xDomain } = useBins({ + fromMillis, + toMillis, + dateHistogram, + minsPerBin, + }); + + return { + loading, + minsPerBin, + timeBins, + getTimeBinByXValue: (xValue: number | undefined) => + xValue === undefined ? undefined : timeBinMap.get(xValue), + xDomain, + handleResize, + }; +}; + +export const useBins = ({ + minsPerBin, + fromMillis, + toMillis, + dateHistogram, +}: { + minsPerBin: number | null; + fromMillis: number; + toMillis: number; + dateHistogram?: MonitorStatusHeatmapBucket[]; +}) => + useMemo((): { timeBins: MonitorStatusTimeBin[]; timeBinMap: Map; xDomain: { min: number; max: number }; @@ -125,14 +155,3 @@ export const useMonitorStatusData = ({ from, to, initialSizeRef }: Props) => { }, }; }, [minsPerBin, fromMillis, toMillis, dateHistogram]); - - return { - loading, - minsPerBin, - timeBins, - getTimeBinByXValue: (xValue: number | undefined) => - xValue === undefined ? undefined : timeBinMap.get(xValue), - xDomain, - handleResize, - }; -}; From 2f76b60b0e2646b71cbc95b0de559154dd947dca Mon Sep 17 00:00:00 2001 From: Giorgos Bamparopoulos Date: Wed, 16 Oct 2024 19:40:00 +0300 Subject: [PATCH 23/30] Update max supported package version (#196551) Update the max supported package version to 3.3.0 Related to https://github.com/elastic/package-spec/pull/818 --- config/serverless.oblt.yml | 2 +- config/serverless.security.yml | 2 +- x-pack/plugins/fleet/server/config.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/serverless.oblt.yml b/config/serverless.oblt.yml index f7e5290717cb3..1146a9280ac4e 100644 --- a/config/serverless.oblt.yml +++ b/config/serverless.oblt.yml @@ -144,7 +144,7 @@ xpack.uptime.service.tls.key: /mnt/elastic-internal/http-certs/tls.key # Fleet specific configuration xpack.fleet.internal.registry.capabilities: ['apm', 'observability', 'uptime'] xpack.fleet.internal.registry.spec.min: '3.0' -xpack.fleet.internal.registry.spec.max: '3.2' +xpack.fleet.internal.registry.spec.max: '3.3' xpack.fleet.internal.registry.kibanaVersionCheckEnabled: false xpack.fleet.internal.registry.excludePackages: [ # Security integrations diff --git a/config/serverless.security.yml b/config/serverless.security.yml index fe86a864d5cf3..5057fa193bef4 100644 --- a/config/serverless.security.yml +++ b/config/serverless.security.yml @@ -76,7 +76,7 @@ telemetry.labels.serverless: security # Fleet specific configuration xpack.fleet.internal.registry.capabilities: ['security'] xpack.fleet.internal.registry.spec.min: '3.0' -xpack.fleet.internal.registry.spec.max: '3.2' +xpack.fleet.internal.registry.spec.max: '3.3' xpack.fleet.internal.registry.kibanaVersionCheckEnabled: false xpack.fleet.internal.registry.excludePackages: [ # Oblt integrations diff --git a/x-pack/plugins/fleet/server/config.ts b/x-pack/plugins/fleet/server/config.ts index 1797c30d15f4d..746498221de55 100644 --- a/x-pack/plugins/fleet/server/config.ts +++ b/x-pack/plugins/fleet/server/config.ts @@ -26,7 +26,7 @@ import { BULK_CREATE_MAX_ARTIFACTS_BYTES } from './services/artifacts/artifacts' const DEFAULT_BUNDLED_PACKAGE_LOCATION = path.join(__dirname, '../target/bundled_packages'); const DEFAULT_GPG_KEY_PATH = path.join(__dirname, '../target/keys/GPG-KEY-elasticsearch'); -const REGISTRY_SPEC_MAX_VERSION = '3.2'; +const REGISTRY_SPEC_MAX_VERSION = '3.3'; export const config: PluginConfigDescriptor = { exposeToBrowser: { From fa92a8ede7bce32456e3d6a6307761b4209248f9 Mon Sep 17 00:00:00 2001 From: Jatin Kathuria Date: Wed, 16 Oct 2024 19:53:49 +0200 Subject: [PATCH 24/30] [Security Solution] Event Renderer Virtualization (#193316) ## Summary This PR implements virtualization when Event Renderers are enabled. Ideally from UX pespective nothing should change but from performance perspective, the event renderers should be scalable. ### Testing checklist 1. UX is working same as before when Event Renderers are enabled. 2. Operations such as increasing page size from `10` to `100` are not taking as much time as before. Below operations can be used to test. a. Closing / Opening Timeline b. Changes `Rows per page` c. Changes tabs from query to any other and back. ### Before In below video, you will notice how long it took to change `pageSize` to 100 and all 100 rows are rendered at once. https://github.com/user-attachments/assets/106669c9-bda8-4b7d-af3f-b64824bde397 ### After https://github.com/user-attachments/assets/356d9e1f-caf1-4f88-9223-0e563939bf6b > [!Note] > 1. Also test in small screen. The table should be scrollable but nothing out of ordinary. > 2. Additionally, try to load data which has `network_flow` process so as to create bigger and varied Event Renderers. --------- Co-authored-by: Cee Chen --- package.json | 2 +- .../security_solution/common/constants.ts | 5 + .../events/stateful_row_renderer/index.tsx | 118 ++++---- .../use_stateful_row_renderer.ts | 1 + .../shared/use_timeline_control_columns.tsx | 106 +++---- ...stom_timeline_data_grid_body.test.tsx.snap | 140 +++++---- .../custom_timeline_data_grid_body.test.tsx | 13 +- .../custom_timeline_data_grid_body.tsx | 271 ++++++++++++++---- .../unified_components/data_table/index.tsx | 53 ++-- .../timeline_event_detail_row.test.tsx | 15 +- .../data_table/timeline_event_detail_row.tsx | 4 +- .../timeline/unified_components/styles.tsx | 9 + .../rule_creation/indicator_match_rule.cy.ts | 11 +- yarn.lock | 8 +- 14 files changed, 491 insertions(+), 265 deletions(-) diff --git a/package.json b/package.json index 0a7c0d6936d0a..2fc8ba6e22aef 100644 --- a/package.json +++ b/package.json @@ -1632,7 +1632,7 @@ "@types/react-router-dom": "^5.3.3", "@types/react-syntax-highlighter": "^15.4.0", "@types/react-test-renderer": "^17.0.2", - "@types/react-virtualized": "^9.21.22", + "@types/react-virtualized": "^9.21.30", "@types/react-window": "^1.8.8", "@types/react-window-infinite-loader": "^1.0.9", "@types/redux-actions": "^2.6.1", diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index 877214641dc1e..2fd83a4849a75 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -513,3 +513,8 @@ export const CASE_ATTACHMENT_ENDPOINT_TYPE_ID = 'endpoint' as const; */ export const MAX_MANUAL_RULE_RUN_LOOKBACK_WINDOW_DAYS = 90; export const MAX_MANUAL_RULE_RUN_BULK_SIZE = 100; + +/* + * Whether it is a Jest environment + */ +export const JEST_ENVIRONMENT = typeof jest !== 'undefined'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_row_renderer/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_row_renderer/index.tsx index b6df692dcabfd..3d50029f70315 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_row_renderer/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_row_renderer/index.tsx @@ -40,69 +40,67 @@ import { useStatefulRowRenderer } from './use_stateful_row_renderer'; * which focuses the current or next row, respectively. * - A screen-reader-only message provides additional context and instruction */ -export const StatefulRowRenderer = ({ - ariaRowindex, - containerRef, - event, - lastFocusedAriaColindex, - rowRenderers, - timelineId, -}: { - ariaRowindex: number; - containerRef: React.MutableRefObject; - event: TimelineItem; - lastFocusedAriaColindex: number; - rowRenderers: RowRenderer[]; - timelineId: string; -}) => { - const { focusOwnership, onFocus, onKeyDown, onOutsideClick } = useStatefulEventFocus({ +export const StatefulRowRenderer = React.memo( + ({ ariaRowindex, - colindexAttribute: ARIA_COLINDEX_ATTRIBUTE, containerRef, + event, lastFocusedAriaColindex, - onColumnFocused: noop, - rowindexAttribute: ARIA_ROWINDEX_ATTRIBUTE, - }); - - const { rowRenderer } = useStatefulRowRenderer({ - data: event.ecs, rowRenderers, - }); - - const content = useMemo( - () => - rowRenderer && ( - // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -
- - - -

{i18n.YOU_ARE_IN_AN_EVENT_RENDERER(ariaRowindex)}

-
- - - {rowRenderer.renderRow({ - data: event.ecs, - isDraggable: true, - scopeId: timelineId, - })} - - -
-
-
- ), - [ + timelineId, + }: { + ariaRowindex: number; + containerRef: React.MutableRefObject; + event: TimelineItem; + lastFocusedAriaColindex: number; + rowRenderers: RowRenderer[]; + timelineId: string; + }) => { + const { focusOwnership, onFocus, onKeyDown, onOutsideClick } = useStatefulEventFocus({ ariaRowindex, - event.ecs, - focusOwnership, - onFocus, - onKeyDown, - onOutsideClick, - rowRenderer, - timelineId, - ] - ); + colindexAttribute: ARIA_COLINDEX_ATTRIBUTE, + containerRef, + lastFocusedAriaColindex, + onColumnFocused: noop, + rowindexAttribute: ARIA_ROWINDEX_ATTRIBUTE, + }); + + const { rowRenderer } = useStatefulRowRenderer({ + data: event.ecs, + rowRenderers, + }); + + const row = useMemo(() => { + const result = rowRenderer?.renderRow({ + data: event.ecs, + isDraggable: false, + scopeId: timelineId, + }); + return result; + }, [rowRenderer, event.ecs, timelineId]); + + const content = useMemo( + () => + rowRenderer && ( + // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions +
+ + + +

{i18n.YOU_ARE_IN_AN_EVENT_RENDERER(ariaRowindex)}

+
+ + {row} + +
+
+
+ ), + [ariaRowindex, focusOwnership, onFocus, onKeyDown, onOutsideClick, rowRenderer, row] + ); + + return content; + } +); - return content; -}; +StatefulRowRenderer.displayName = 'StatefulRowRenderer'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_row_renderer/use_stateful_row_renderer.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_row_renderer/use_stateful_row_renderer.ts index 504cbe94a9102..7648c94288907 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_row_renderer/use_stateful_row_renderer.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_row_renderer/use_stateful_row_renderer.ts @@ -17,6 +17,7 @@ interface UseStatefulRowRendererArgs { export function useStatefulRowRenderer(args: UseStatefulRowRendererArgs) { const { data, rowRenderers } = args; + const rowRenderer = useMemo(() => getRowRenderer({ data, rowRenderers }), [data, rowRenderers]); const result = useMemo( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_control_columns.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_control_columns.tsx index 662baa8e6b665..beeaadb7829c8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_control_columns.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_control_columns.tsx @@ -5,10 +5,11 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React, { useMemo, useEffect } from 'react'; import type { EuiDataGridCellValueElementProps } from '@elastic/eui'; import type { SortColumnTable } from '@kbn/securitysolution-data-table'; import type { TimelineItem } from '@kbn/timelines-plugin/common'; +import { JEST_ENVIRONMENT } from '../../../../../../common/constants'; import { useLicense } from '../../../../../common/hooks/use_license'; import { SourcererScopeName } from '../../../../../sourcerer/store/model'; import { useSourcererDataView } from '../../../../../sourcerer/containers'; @@ -21,6 +22,7 @@ import { TimelineControlColumnCellRender } from '../../unified_components/data_t import type { ColumnHeaderOptions } from '../../../../../../common/types'; import { useTimelineColumns } from './use_timeline_columns'; import type { UnifiedTimelineDataGridCellContext } from '../../types'; +import { useTimelineUnifiedDataTableContext } from '../../unified_components/data_table/use_timeline_unified_data_table_context'; interface UseTimelineControlColumnArgs { columns: ColumnHeaderOptions[]; @@ -59,6 +61,58 @@ export const useTimelineControlColumn = ({ const ACTION_BUTTON_COUNT = isEnterprisePlus ? 6 : 5; const { localColumns } = useTimelineColumns(columns); + const RowCellRender = useMemo( + () => + function TimelineControlColumnCellRenderer( + props: EuiDataGridCellValueElementProps & UnifiedTimelineDataGridCellContext + ) { + const ctx = useTimelineUnifiedDataTableContext(); + + useEffect(() => { + props.setCellProps({ + className: + ctx.expanded?.id === events[props.rowIndex]?._id + ? 'unifiedDataTable__cell--expanded' + : '', + }); + }); + + /* + * In some cases, when number of events is updated + * but new table is not yet rendered it can result + * in the mismatch between the number of events v/s + * the number of rows in the table currently rendered. + * + * */ + if ('rowIndex' in props && props.rowIndex >= events.length) return <>; + return ( + + ); + }, + [events, timelineId, refetch, pinnedEventIds, eventIdToNoteIds, onToggleShowNotes] + ); + // We need one less when the unified components are enabled because the document expand is provided by the unified data table const UNIFIED_COMPONENTS_ACTION_BUTTON_COUNT = ACTION_BUTTON_COUNT - 1; return useMemo(() => { @@ -84,49 +138,7 @@ export const useTimelineControlColumn = ({ /> ); }, - rowCellRender: ( - props: EuiDataGridCellValueElementProps & UnifiedTimelineDataGridCellContext - ) => { - /* - * In some cases, when number of events is updated - * but new table is not yet rendered it can result - * in the mismatch between the number of events v/s - * the number of rows in the table currently rendered. - * - * */ - if ('rowIndex' in props && props.rowIndex >= events.length) return <>; - props.setCellProps({ - className: - props.expandedEventId === events[props.rowIndex]?._id - ? 'unifiedDataTable__cell--expanded' - : '', - }); - - return ( - - ); - }, + rowCellRender: JEST_ENVIRONMENT ? RowCellRender : React.memo(RowCellRender), })); } else { return getDefaultControlColumn(ACTION_BUTTON_COUNT).map((x) => ({ @@ -142,11 +154,7 @@ export const useTimelineControlColumn = ({ sort, activeTab, timelineId, - refetch, - events, - pinnedEventIds, - eventIdToNoteIds, - onToggleShowNotes, ACTION_BUTTON_COUNT, + RowCellRender, ]); }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/__snapshots__/custom_timeline_data_grid_body.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/__snapshots__/custom_timeline_data_grid_body.test.tsx.snap index d54175194b748..d5a892b4e54ce 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/__snapshots__/custom_timeline_data_grid_body.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/__snapshots__/custom_timeline_data_grid_body.test.tsx.snap @@ -2,32 +2,35 @@ exports[`CustomTimelineDataGridBody should render exactly as snapshots 1`] = ` .c0 { - width: -webkit-fit-content; - width: -moz-fit-content; - width: fit-content; - border-bottom: 1px solid 1px solid #343741; -} - -.c0 . euiDataGridRowCell--controlColumn { - height: auto; - min-height: 34px; + width: 100%; + height: 100%; + border-bottom: 1px solid #343741; } .c0 .udt--customRow { border-radius: 0; padding: 6px; - max-width: 1200px; - width: 85vw; + max-width: 1000px; } -.c0 .euiCommentEvent__body { - background-color: #1d1e24; +.c0 .euiDataGridRowCell--lastColumn.euiDataGridRowCell--controlColumn .euiDataGridRowCell__content { + width: 1000px; + max-width: 1000px; + overflow-x: auto; + -webkit-scrollbar-width: thin; + -moz-scrollbar-width: thin; + -ms-scrollbar-width: thin; + scrollbar-width: thin; + -webkit-scroll-padding: 0 0 0 0,; + -moz-scroll-padding: 0 0 0 0,; + -ms-scroll-padding: 0 0 0 0,; + scroll-padding: 0 0 0 0,; } -.c0:has(.unifiedDataTable__cell--expanded) .euiDataGridRowCell--firstColumn, -.c0:has(.unifiedDataTable__cell--expanded) .euiDataGridRowCell--lastColumn, -.c0:has(.unifiedDataTable__cell--expanded) .euiDataGridRowCell--controlColumn, -.c0:has(.unifiedDataTable__cell--expanded) .udt--customRow { +.c0 .euiDataGridRow:has(.unifiedDataTable__cell--expanded) .euiDataGridRowCell--firstColumn, +.c0 .euiDataGridRow:has(.unifiedDataTable__cell--expanded) .euiDataGridRowCell--lastColumn, +.c0 .euiDataGridRow:has(.unifiedDataTable__cell--expanded) .euiDataGridRowCell--controlColumn, +.c0 .euiDataGridRow:has(.unifiedDataTable__cell--expanded) .udt--customRow { background-color: #2e2d25; } @@ -42,47 +45,76 @@ exports[`CustomTimelineDataGridBody should render exactly as snapshots 1`] = `
-
- Cell-0-0 -
-
- Cell-0-1 +
+
+
+
+
+
+ Cell-0-0 +
+
+ Cell-0-1 +
+
+ Cell-0-2 +
+
+
+ Cell-0-3 +
+
+
+
+
+
+
+ Cell-1-0 +
+
+ Cell-1-1 +
+
+ Cell-1-2 +
+
+
+ Cell-1-3 +
+
+
+
-
- Cell-0-2 -
-
-
- Cell-0-3 -
-
-
-
-
- Cell-1-0 -
-
- Cell-1-1 -
-
- Cell-1-2 -
-
-
- Cell-1-3
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.test.tsx index b6d7f52f2d92f..cfdb2b0d2dbf9 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.test.tsx @@ -48,10 +48,10 @@ const defaultProps: CustomTimelineDataGridBodyProps = { visibleColumns: mockVisibleColumns, headerRow: <>, footerRow: null, - gridWidth: 0, + gridWidth: 1000, }; -const renderTestComponents = (props?: CustomTimelineDataGridBodyProps) => { +const renderTestComponents = (props?: Partial) => { const finalProps = props ? { ...defaultProps, ...props } : defaultProps; return render( @@ -88,8 +88,15 @@ describe('CustomTimelineDataGridBody', () => { (useStatefulRowRenderer as jest.Mock).mockReturnValueOnce({ canShowRowRenderer: true, }); - const { getByText, queryByText } = renderTestComponents(); + const { getByTestId, getByText, queryByText } = renderTestComponents(); + + expect(getByTestId('customGridRowsContainer')).toBeVisible(); expect(queryByText('Cell-0-3')).toBeFalsy(); expect(getByText('Cell-1-3')).toBeInTheDocument(); }); + + it('should not render grid if gridWidth is 0', () => { + const { queryByTestId } = renderTestComponents({ gridWidth: 0 }); + expect(queryByTestId('customGridRowsContainer')).not.toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.tsx index 559dcbf10c4e6..d03958bba5b62 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.tsx @@ -5,18 +5,24 @@ * 2.0. */ -import type { EuiDataGridCustomBodyProps } from '@elastic/eui'; +import type { EuiDataGridCustomBodyProps, EuiDataGridRowHeightsOptions } from '@elastic/eui'; import type { DataTableRecord } from '@kbn/discover-utils/types'; -import type { EuiTheme } from '@kbn/react-kibana-context-styled'; +import { type EuiTheme } from '@kbn/react-kibana-context-styled'; import type { TimelineItem } from '@kbn/timelines-plugin/common'; -import type { FC } from 'react'; -import React, { memo, useMemo } from 'react'; +import type { CSSProperties, FC, PropsWithChildren } from 'react'; +import React, { memo, useMemo, useState, useEffect, useRef, useCallback } from 'react'; import styled from 'styled-components'; +import { VariableSizeList } from 'react-window'; +import { EuiAutoSizer, useEuiTheme } from '@elastic/eui'; import type { RowRenderer } from '../../../../../../common/types'; import { TIMELINE_EVENT_DETAIL_ROW_ID } from '../../body/constants'; import { useStatefulRowRenderer } from '../../body/events/stateful_row_renderer/use_stateful_row_renderer'; import { getEventTypeRowClassName } from './get_event_type_row_classname'; +const defaultAutoHeight: EuiDataGridRowHeightsOptions = { + defaultHeight: 'auto', +}; + export type CustomTimelineDataGridBodyProps = EuiDataGridCustomBodyProps & { rows: Array | undefined; enabledRowRenderers: RowRenderer[]; @@ -24,9 +30,46 @@ export type CustomTimelineDataGridBodyProps = EuiDataGridCustomBodyProps & { refetch?: () => void; }; +const VirtualizedCustomDataGridContainer = styled.div<{ + $maxWidth?: number; +}>` + width: 100%; + height: 100%; + border-bottom: ${(props) => (props.theme as EuiTheme).eui.euiBorderThin}; + .udt--customRow { + border-radius: 0; + padding: ${(props) => (props.theme as EuiTheme).eui.euiDataGridCellPaddingM}; + max-width: ${(props) => props.$maxWidth}px; + } + + .euiDataGridRowCell--lastColumn.euiDataGridRowCell--controlColumn .euiDataGridRowCell__content { + width: ${(props) => props.$maxWidth}px; + max-width: ${(props) => props.$maxWidth}px; + overflow-x: auto; + scrollbar-width: thin; + scroll-padding: 0 0 0 0, + } + + .euiDataGridRow:has(.unifiedDataTable__cell--expanded) { + .euiDataGridRowCell--firstColumn, + .euiDataGridRowCell--lastColumn, + .euiDataGridRowCell--controlColumn, + .udt--customRow { + ${({ theme }) => `background-color: ${theme.eui.euiColorHighlight};`} + } + } + } +`; + // THE DataGrid Row default is 34px, but we make ours 40 to account for our row actions const DEFAULT_UDT_ROW_HEIGHT = 34; +const SCROLLBAR_STYLE: CSSProperties = { + scrollbarWidth: 'thin', + scrollPadding: '0 0 0 0', + overflow: 'auto', +}; + /** * * In order to render the additional row with every event ( which displays the row-renderer, notes and notes editor) @@ -44,40 +87,170 @@ export const CustomTimelineDataGridBody: FC = m function CustomTimelineDataGridBody(props) { const { Cell, - headerRow, - footerRow, visibleColumns, visibleRowData, rows, rowHeight, enabledRowRenderers, refetch, + setCustomGridBodyProps, + headerRow, + footerRow, + gridWidth, } = props; + const { euiTheme } = useEuiTheme(); + + // // Set custom props onto the grid body wrapper + const bodyRef = useRef(null); + useEffect(() => { + setCustomGridBodyProps({ + ref: bodyRef, + style: { + width: '100%', + height: '100%', + overflowY: 'hidden', + scrollbarColor: `${euiTheme.colors.mediumShade} ${euiTheme.colors.lightestShade}`, + }, + }); + }, [setCustomGridBodyProps, euiTheme.colors.mediumShade, euiTheme.colors.lightestShade]); + const visibleRows = useMemo( () => (rows ?? []).slice(visibleRowData.startRow, visibleRowData.endRow), [rows, visibleRowData] ); + const listRef = useRef>(null); + + const rowHeights = useRef([]); + + const setRowHeight = useCallback((index: number, height: number) => { + if (rowHeights.current[index] === height) return; + listRef.current?.resetAfterIndex(index); + + rowHeights.current[index] = height; + }, []); + + const getRowHeight = useCallback((index: number) => { + return rowHeights.current[index] ?? 100; + }, []); + + /* + * + * There is a difference between calculatedWidth & gridWidth + * + * gridWidth is the width of the grid as per the screen size + * + * calculatedWidth is the width of the grid that is calculated by EUI and represents + * the actual width of the grid based on the content of the grid. ( Sum of the width of all columns) + * + * For example, screensize can be variable but calculatedWidth can be much more than that + * with grid having a horizontal scrollbar + * + * + * */ + const [calculatedWidth, setCalculatedWidth] = useState(gridWidth); + + useEffect(() => { + /* + * Any time gridWidth(available screen size) is changed, we need to re-check + * to see if EUI has changed the width of the grid + * + */ + if (!bodyRef) return; + const headerRowRef = bodyRef?.current?.querySelector('.euiDataGridHeader[role="row"]'); + setCalculatedWidth((prev) => + headerRowRef?.clientWidth && headerRowRef?.clientWidth !== prev + ? headerRowRef?.clientWidth + : prev + ); + }, [gridWidth]); + + const innerRowContainer = useMemo(() => { + const InnerComp = React.forwardRef< + HTMLDivElement, + PropsWithChildren<{ style: CSSProperties }> + >(({ children, style, ...rest }, ref) => { + return ( + <> + {headerRow} +
+ {children} +
+ + {footerRow} + + ); + }); + + InnerComp.displayName = 'InnerRowContainer'; + + return React.memo(InnerComp); + }, [headerRow, footerRow]); + return ( - <> - {headerRow} - {visibleRows.map((row, rowIndex) => { - return ( - - ); - })} - {footerRow} - + + + {({ height }) => { + return ( + <> + { + /** + * whenever timeline is minimized, VariableList is re-rendered which causes delay, + * so below code makes sure that grid is only rendered when gridWidth is not 0 + */ + gridWidth !== 0 && ( + <> + + {({ index, style }) => { + return ( +
+ +
+ ); + }} +
+ + ) + } + + ); + }} +
+
); } ); @@ -85,41 +258,17 @@ export const CustomTimelineDataGridBody: FC = m /** * * A Simple Wrapper component for displaying a custom grid row + * Generating CSS on this row puts a huge performance overhead on the grid as each row much styled individually. + * If possible, try to use the styles either in ../styles.tsx or in the parent component * */ + const CustomGridRow = styled.div.attrs<{ className?: string; }>((props) => ({ className: `euiDataGridRow ${props.className ?? ''}`, role: 'row', -}))` - width: fit-content; - border-bottom: 1px solid ${(props) => (props.theme as EuiTheme).eui.euiBorderThin}; - . euiDataGridRowCell--controlColumn { - height: ${(props: { $cssRowHeight: string }) => props.$cssRowHeight}; - min-height: ${DEFAULT_UDT_ROW_HEIGHT}px; - } - .udt--customRow { - border-radius: 0; - padding: ${(props) => (props.theme as EuiTheme).eui.euiDataGridCellPaddingM}; - max-width: ${(props) => (props.theme as EuiTheme).eui.euiPageDefaultMaxWidth}; - width: 85vw; - } - - .euiCommentEvent__body { - background-color: ${(props) => (props.theme as EuiTheme).eui.euiColorEmptyShade}; - } - - &:has(.unifiedDataTable__cell--expanded) { - .euiDataGridRowCell--firstColumn, - .euiDataGridRowCell--lastColumn, - .euiDataGridRowCell--controlColumn, - .udt--customRow { - ${({ theme }) => `background-color: ${theme.eui.euiColorHighlight};`} - } - } - } -`; +}))``; /* below styles as per : https://eui.elastic.co/#/tabular-content/data-grid-advanced#custom-body-renderer */ const CustomGridRowCellWrapper = styled.div.attrs<{ @@ -138,6 +287,7 @@ const CustomGridRowCellWrapper = styled.div.attrs<{ type CustomTimelineDataGridSingleRowProps = { rowData: DataTableRecord & TimelineItem; rowIndex: number; + setRowHeight: (index: number, height: number) => void; } & Pick< CustomTimelineDataGridBodyProps, 'visibleColumns' | 'Cell' | 'enabledRowRenderers' | 'refetch' | 'rowHeight' @@ -168,13 +318,24 @@ const CustomDataGridSingleRow = memo(function CustomDataGridSingleRow( visibleColumns, Cell, rowHeight: rowHeightMultiple = 0, + setRowHeight, } = props; + const { canShowRowRenderer } = useStatefulRowRenderer({ data: rowData.ecs, rowRenderers: enabledRowRenderers, }); + const rowRef = useRef(null); + + useEffect(() => { + if (rowRef.current) { + setRowHeight(rowIndex, rowRef.current.offsetHeight); + } + }, [rowIndex, setRowHeight]); + const cssRowHeight: string = calculateRowHeightInPixels(rowHeightMultiple - 1); + /** * removes the border between the actual row ( timelineEvent) and `TimelineEventDetail` row * which renders the row-renderer, notes and notes editor @@ -194,12 +355,11 @@ const CustomDataGridSingleRow = memo(function CustomDataGridSingleRow( return ( {visibleColumns.map((column, colIndex) => { - // Skip the expanded row cell - we'll render it manually outside of the flex wrapper if (column.id !== TIMELINE_EVENT_DETAIL_ROW_ID) { return ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx index e4862fe8d72f6..875c147d6a700 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx @@ -12,8 +12,13 @@ import type { DataTableRecord } from '@kbn/discover-utils/types'; import type { UnifiedDataTableProps } from '@kbn/unified-data-table'; import { UnifiedDataTable, DataLoadingState } from '@kbn/unified-data-table'; import type { DataView } from '@kbn/data-views-plugin/public'; -import type { EuiDataGridCustomBodyProps, EuiDataGridProps } from '@elastic/eui'; +import type { + EuiDataGridControlColumn, + EuiDataGridCustomBodyProps, + EuiDataGridProps, +} from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { JEST_ENVIRONMENT } from '../../../../../../common/constants'; import { useOnExpandableFlyoutClose } from '../../../../../flyout/shared/hooks/use_on_expandable_flyout_close'; import { DocumentDetailsRightPanelKey } from '../../../../../flyout/document_details/shared/constants/panel_keys'; import { selectTimelineById } from '../../../../store/selectors'; @@ -43,7 +48,6 @@ import { transformTimelineItemToUnifiedRows } from '../utils'; import { TimelineEventDetailRow } from './timeline_event_detail_row'; import { CustomTimelineDataGridBody } from './custom_timeline_data_grid_body'; import { TIMELINE_EVENT_DETAIL_ROW_ID } from '../../body/constants'; -import type { UnifiedTimelineDataGridCellContext } from '../../types'; export const SAMPLE_SIZE_SETTING = 500; const DataGridMemoized = React.memo(UnifiedDataTable); @@ -288,6 +292,23 @@ export const TimelineDataTableComponent: React.FC = memo( return rowRenderers.filter((rowRenderer) => !excludedRowRendererIds.includes(rowRenderer.id)); }, [excludedRowRendererIds, rowRenderers]); + const TimelineEventDetailRowRendererComp = useMemo( + () => + function TimelineEventDetailRowRenderer(props) { + const { rowIndex, ...restProps } = props; + return ( + + ); + }, + [tableRows, timelineId, enabledRowRenderers] + ); + /** * Ref: https://eui.elastic.co/#/tabular-content/data-grid-advanced#custom-body-renderer */ @@ -295,31 +316,20 @@ export const TimelineDataTableComponent: React.FC = memo( () => [ { id: TIMELINE_EVENT_DETAIL_ROW_ID, - // The header cell should be visually hidden, but available to screen readers width: 0, + // The header cell should be visually hidden, but available to screen readers headerCellRender: () => <>, headerCellProps: { className: 'euiScreenReaderOnly' }, // The footer cell can be hidden to both visual & SR users, as it does not contain meaningful information footerCellProps: { style: { display: 'none' } }, - // When rendering this custom cell, we'll want to override - // the automatic width/heights calculated by EuiDataGrid - rowCellRender: (props) => { - const { rowIndex, ...restProps } = props; - return ( - - ); - }, + rowCellRender: JEST_ENVIRONMENT + ? TimelineEventDetailRowRendererComp + : React.memo(TimelineEventDetailRowRendererComp), }, ], - [enabledRowRenderers, tableRows, timelineId] + [TimelineEventDetailRowRendererComp] ); /** @@ -352,12 +362,6 @@ export const TimelineDataTableComponent: React.FC = memo( [tableRows, enabledRowRenderers, rowHeight, refetch] ); - const cellContext: UnifiedTimelineDataGridCellContext = useMemo(() => { - return { - expandedEventId: expandedDoc?.id, - }; - }, [expandedDoc]); - const finalRenderCustomBodyCallback = useMemo(() => { return enabledRowRenderers.length > 0 ? renderCustomBodyCallback : undefined; }, [enabledRowRenderers.length, renderCustomBodyCallback]); @@ -419,7 +423,6 @@ export const TimelineDataTableComponent: React.FC = memo( renderCustomGridBody={finalRenderCustomBodyCallback} trailingControlColumns={finalTrailControlColumns} externalControlColumns={leadingControlColumns} - cellContext={cellContext} /> diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/timeline_event_detail_row.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/timeline_event_detail_row.test.tsx index a4de0c7dfa318..92070ec1fada0 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/timeline_event_detail_row.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/timeline_event_detail_row.test.tsx @@ -18,7 +18,14 @@ const mockData = structuredClone(mockTimelineData); const setCellPropsMock = jest.fn(); -jest.mock('../../body/events/stateful_row_renderer'); +jest.mock('../../body/events/stateful_row_renderer', () => { + return { + StatefulRowRenderer: jest.fn(), + }; +}); + +const StatefulRowRendererMock = StatefulRowRenderer as unknown as jest.Mock; + jest.mock('./use_timeline_unified_data_table_context'); const renderTestComponent = (props: Partial = {}) => { @@ -44,7 +51,7 @@ const renderTestComponent = (props: Partial = {}) = describe('TimelineEventDetailRow', () => { beforeEach(() => { - (StatefulRowRenderer as jest.Mock).mockReturnValue(
{'Test Row Renderer'}
); + StatefulRowRendererMock.mockReturnValue(
{'Test Row Renderer'}
); (useTimelineUnifiedDataTableContext as jest.Mock).mockReturnValue({ expanded: { id: undefined }, @@ -60,7 +67,7 @@ describe('TimelineEventDetailRow', () => { expect(setCellPropsMock).toHaveBeenCalledWith({ className: '', - style: { width: '100%', height: 'auto' }, + style: { width: '100%', height: undefined, overflowX: 'auto' }, }); expect(getByText('Test Row Renderer')).toBeVisible(); @@ -82,7 +89,7 @@ describe('TimelineEventDetailRow', () => { expect(setCellPropsMock).toHaveBeenCalledWith({ className: 'unifiedDataTable__cell--expanded', - style: { width: '100%', height: 'auto' }, + style: { width: '100%', height: undefined, overflowX: 'auto' }, }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/timeline_event_detail_row.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/timeline_event_detail_row.tsx index 72a33af797210..9a3bc97254962 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/timeline_event_detail_row.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/timeline_event_detail_row.tsx @@ -60,7 +60,7 @@ export const TimelineEventDetailRow: React.FC = mem useEffect(() => { setCellProps?.({ className: ctx.expanded?.id === event._id ? 'unifiedDataTable__cell--expanded' : '', - style: { width: '100%', height: 'auto' }, + style: { width: '100%', height: undefined, overflowX: 'auto' }, }); }, [ctx.expanded?.id, setCellProps, rowIndex, event._id]); @@ -72,7 +72,7 @@ export const TimelineEventDetailRow: React.FC = mem alignItems="center" data-test-subj={`timeline-row-renderer-${rowIndex}`} > - + + `scrollbar-color: ${theme.eui.euiColorMediumShade} ${theme.eui.euiColorLightShade}`}; + } + .udtTimeline [data-gridcell-column-id|='select'] { border-right: none; } @@ -182,6 +187,10 @@ export const StyledTimelineUnifiedDataTable = styled.div.attrs(({ className = '' align-items: baseline; } + .euiDataGrid__customRenderBody { + scrollbar-color: transparent !important; + } + ${leadingActionsColumnStyles} `; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule.cy.ts index d359a50c00c3e..8d44be4dc3aaf 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule.cy.ts @@ -503,8 +503,6 @@ describe('indicator match', { tags: ['@ess', '@serverless', '@skipInServerlessMK }); it('Investigate alert in timeline', () => { - const accessibilityText = `Press enter for options, or press space to begin dragging.`; - loadPrepackagedTimelineTemplates(); createRule(getNewThreatIndicatorRule({ rule_id: 'rule_testing', enabled: true })).then( (rule) => visitRuleDetailsPage(rule.body.id) @@ -525,14 +523,9 @@ describe('indicator match', { tags: ['@ess', '@serverless', '@skipInServerlessMK cy.get(INDICATOR_MATCH_ROW_RENDER).should( 'have.text', - `threat.enrichments.matched.field${ - getNewThreatIndicatorRule().threat_mapping[0].entries[0].field - }${accessibilityText}matched${ - getNewThreatIndicatorRule().threat_mapping[0].entries[0].field - }${ + `${getNewThreatIndicatorRule().threat_mapping[0].entries[0].field}matched${ indicatorRuleMatchingDoc.atomic - }${accessibilityText}threat.enrichments.matched.typeindicator_match_rule${accessibilityText}provided` + - ` byfeed.nameAbuseCH malware${accessibilityText}` + }indicator_match_ruleprovided` + ` byAbuseCH malware` ); }); }); diff --git a/yarn.lock b/yarn.lock index ed8af28c675f4..fa3904c57939e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11316,10 +11316,10 @@ dependencies: "@types/react" "*" -"@types/react-virtualized@^9.21.22": - version "9.21.22" - resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.21.22.tgz#5ba39b29869200620a6bf2069b8393f258a9c1e2" - integrity sha512-YRifyCKnBG84+J/Hny0f3bo8BRrcNT74CvsAVpQpZcS83fdC7lP7RfzwL2ND8/ihhpnDFL1IbxJ9MpQNaKUDuQ== +"@types/react-virtualized@^9.21.30": + version "9.21.30" + resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.21.30.tgz#ba39821bcb2487512a8a2cdd9fbdb5e6fc87fedb" + integrity sha512-4l2TFLQ8BCjNDQlvH85tU6gctuZoEdgYzENQyZHpgTHU7hoLzYgPSOALMAeA58LOWua8AzC6wBivPj1lfl6JgQ== dependencies: "@types/prop-types" "*" "@types/react" "*" From 2eff6d1046c94252ac0cc52f78859101383e6f71 Mon Sep 17 00:00:00 2001 From: Jatin Kathuria Date: Wed, 16 Oct 2024 19:56:41 +0200 Subject: [PATCH 25/30] [ Security Solution ]Re-organize the Investigations api integration test for MKI (#194707) ## Summary This is Part 1 of the in resolving the issue : https://github.com/elastic/kibana/issues/183645 . This PR re-organizes investigations API tests so that they can be run in Serveless MKI at both `basic/essentials` and `complete` licenses. ## How to test this PR Below are the commands that are affected by this change and you can test the PR by running below commands. Each commands sets up the test environment and give you a command to run tests. Please run those tests to see if everything is okay. An example is shown in below screenshot. grafik |Module|Deployment|License|Command| |--|--|--|--| |Timelines|ESS|basic|`yarn investigations:basic:timeline:server:ess`| |Timelines|ESS|Trial|`yarn investigations:timeline:server:ess`| |Timelines|Serverless|basic|`yarn investigations:basic:timeline:server:serverless`| |Timelines|Serverless|Trial|`yarn investigations:timeline:server:serverless`| |Saved Objects|ESS|basic|`yarn investigations:basic:saved-objects:server:ess`| |Saved Objects|ESS|Trial|`yarn investigations:saved-objects:server:ess`| |Saved Objects|Serverless|basic|`yarn investigations:basic:saved-objects:server:serverless`| |Saved Objects|Serverless|Trial|`yarn investigations:saved-objects:server:serverless`| --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .buildkite/ftr_security_stateful_configs.yml | 8 +- .../package.json | 19 + .../configs/ess.config.ts} | 6 +- .../configs/serverless.config.ts | 23 + .../draft_timeline.ts | 0 .../helpers.ts | 0 .../index.ts | 0 .../notes.ts | 0 .../pinned_events.ts | 0 .../timeline.ts | 0 .../configs/ess.config.ts | 2 +- .../configs/serverless.config.ts | 2 +- .../configs/ess.config.ts} | 2 +- .../configs/serverless.config.ts | 23 + .../mocks/timeline_details.ts | 0 .../security_and_spaces/tests/basic/events.ts | 398 ------------------ .../security_and_spaces/tests/basic/index.ts | 29 -- .../security_and_spaces/tests/trial/events.ts | 279 ------------ .../security_and_spaces/tests/trial/index.ts | 99 ----- .../tests/events.ts | 6 +- .../tests/basic => tests}/import_timelines.ts | 4 +- .../tests/index.ts | 7 +- .../install_prepackaged_timelines.ts | 42 +- .../tests/timeline.ts | 10 +- .../tests/timeline_details.ts | 4 +- .../tests/timeline_migrations.ts | 6 +- .../configs/ess.config.ts | 2 +- .../configs/serverless.config.ts | 2 +- .../tsconfig.json | 1 - 29 files changed, 120 insertions(+), 854 deletions(-) rename x-pack/test/security_solution_api_integration/test_suites/investigation/{timeline/security_and_spaces/configs/ess.trial.config.ts => saved_objects/basic_license_essentials_tier/configs/ess.config.ts} (79%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/basic_license_essentials_tier/configs/serverless.config.ts rename x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/{trial_license_complete_tier => tests}/draft_timeline.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/{trial_license_complete_tier => tests}/helpers.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/{trial_license_complete_tier => tests}/index.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/{trial_license_complete_tier => tests}/notes.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/{trial_license_complete_tier => tests}/pinned_events.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/{trial_license_complete_tier => tests}/timeline.ts (100%) rename x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/{security_and_spaces/configs/ess.basic.config.ts => basic_license_essentials_tier/configs/ess.config.ts} (94%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/basic_license_essentials_tier/configs/serverless.config.ts rename x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/{trial_license_complete_tier => }/mocks/timeline_details.ts (100%) delete mode 100644 x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/events.ts delete mode 100644 x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/index.ts delete mode 100644 x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/trial/events.ts delete mode 100644 x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/trial/index.ts rename x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/{trial_license_complete_tier => }/tests/events.ts (94%) rename x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/{security_and_spaces/tests/basic => tests}/import_timelines.ts (98%) rename x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/{trial_license_complete_tier => }/tests/index.ts (65%) rename x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/{security_and_spaces/tests/basic => tests}/install_prepackaged_timelines.ts (63%) rename x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/{trial_license_complete_tier => }/tests/timeline.ts (93%) rename x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/{trial_license_complete_tier => }/tests/timeline_details.ts (94%) rename x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/{trial_license_complete_tier => }/tests/timeline_migrations.ts (97%) diff --git a/.buildkite/ftr_security_stateful_configs.yml b/.buildkite/ftr_security_stateful_configs.yml index a2390fa2bd27f..dbe529596102e 100644 --- a/.buildkite/ftr_security_stateful_configs.yml +++ b/.buildkite/ftr_security_stateful_configs.yml @@ -69,10 +69,14 @@ enabled: - x-pack/test/security_solution_api_integration/test_suites/explore/network/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/explore/users/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/explore/overview/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/basic_license_essentials_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/configs/ess.config.ts - - x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/configs/ess.basic.config.ts - - x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/configs/ess.trial.config.ts + - x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/basic_license_essentials_tier/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/sources/indices/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/artifacts/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/edr_workflows/authentication/trial_license_complete_tier/configs/ess.config.ts diff --git a/x-pack/test/security_solution_api_integration/package.json b/x-pack/test/security_solution_api_integration/package.json index 1649c79f52a7d..18c4eba5fe79f 100644 --- a/x-pack/test/security_solution_api_integration/package.json +++ b/x-pack/test/security_solution_api_integration/package.json @@ -39,6 +39,10 @@ "initialize-server:edr-workflows": "node ./scripts/index.js server edr_workflows trial_license_complete_tier", "run-tests:edr-workflows": "node ./scripts/index.js runner edr_workflows trial_license_complete_tier", + + "initialize-server:investigations:basic_essentials": "node scripts/index.js server investigation basic_license_essentials_tier", + "run-tests:investigations:basic_essentials": "node scripts/index.js runner investigation basic_license_essentials_tier", + "initialize-server:investigations": "node scripts/index.js server investigation trial_license_complete_tier", "run-tests:investigations": "node scripts/index.js runner investigation trial_license_complete_tier", @@ -377,6 +381,14 @@ "investigations:timeline:server:ess": "npm run initialize-server:investigations timeline ess", "investigations:timeline:runner:ess": "npm run run-tests:investigations timeline ess essEnv", + + "investigations:basic:timeline:server:ess": "npm run initialize-server:investigations:basic_essentials timeline ess", + "investigations:basic:timeline:server:serverless": "npm run initialize-server:investigations:basic_essentials timeline serverless", + "investigations:basic:timeline:runner:ess": "npm run run-tests:investigations:basic_essentials timeline ess essEnv", + "investigations:basic:timeline:runner:serverless": "npm run run-tests:investigations:basic_essentials timeline serverless serverlessEnv", + "investigations:basic:timeline:runner:qa:serverless": "npm run run-tests:investigations:basic_essentials timeline serverless qaPeriodicEnv", + "investigations:basic:timeline:runner:qa:serverless:release": "npm run run-tests:investigations:basic_essentials timeline serverless qaEnv", + "investigations:saved-objects:server:serverless": "npm run initialize-server:investigations saved_objects serverless", "investigations:saved-objects:runner:serverless": "npm run run-tests:investigations saved_objects serverless serverlessEnv", "investigations:saved-objects:runner:qa:serverless": "npm run run-tests:investigations saved_objects serverless qaPeriodicEnv", @@ -384,6 +396,13 @@ "investigations:saved-objects:server:ess": "npm run initialize-server:investigations saved_objects ess", "investigations:saved-objects:runner:ess": "npm run run-tests:investigations saved_objects ess essEnv", + "investigations:basic:saved-objects:server:serverless": "npm run initialize-server:investigations:basic_essentials saved_objects serverless", + "investigations:basic:saved-objects:runner:serverless": "npm run run-tests:investigations:basic_essentials saved_objects serverless serverlessEnv", + "investigations:basic:saved-objects:runner:qa:serverless": "npm run run-tests:investigations:basic_essentials saved_objects serverless qaPeriodicEnv", + "investigations:basic:saved-objects:runner:qa:serverless:release": "npm run run-tests:investigations:basic_essentials saved_objects serverless qaEnv", + "investigations:basic:saved-objects:server:ess": "npm run initialize-server:investigations:basic_essentials saved_objects ess", + "investigations:basic:saved-objects:runner:ess": "npm run run-tests:investigations:basic_essentials saved_objects ess essEnv", + "explore:hosts:server:serverless": "npm run intialize-server:explore hosts serverless", "explore:hosts:runner:serverless": "npm run run-tests:explore hosts serverless serverlessEnv", "explore:hosts:runner:qa:serverless": "npm run run-tests:explore hosts serverless qaPeriodicEnv", diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/configs/ess.trial.config.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/basic_license_essentials_tier/configs/ess.config.ts similarity index 79% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/configs/ess.trial.config.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/basic_license_essentials_tier/configs/ess.config.ts index ad8b3a9ddcd39..d4a5b5f5a80c8 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/configs/ess.trial.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/basic_license_essentials_tier/configs/ess.config.ts @@ -8,7 +8,7 @@ import { FtrConfigProviderContext } from '@kbn/test'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { const functionalConfig = await readConfigFile( - require.resolve('../../../../../config/ess/config.base.trial') + require.resolve('../../../../../config/ess/config.base.basic') ); return { @@ -20,9 +20,9 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { `--xpack.securitySolution.enableExperimental=${JSON.stringify([])}`, ], }, - testFiles: [require.resolve('../tests/trial')], + testFiles: [require.resolve('../../tests')], junit: { - reportName: 'Timeline Integration Tests - ESS Env - Trial License', + reportName: 'Saved Objects Integration Tests - ESS Env - Basic License', }, }; } diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/basic_license_essentials_tier/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/basic_license_essentials_tier/configs/serverless.config.ts new file mode 100644 index 0000000000000..5e70e9b7717d5 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/basic_license_essentials_tier/configs/serverless.config.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../config/serverless/config.base'; + +export default createTestConfig({ + kbnTestServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify([])}`, + `--xpack.securitySolutionServerless.productTypes=${JSON.stringify([ + { product_line: 'security', product_tier: 'essentials' }, + { product_line: 'endpoint', product_tier: 'essentials' }, + { product_line: 'cloud', product_tier: 'essentials' }, + ])}`, + ], + testFiles: [require.resolve('../../tests')], + junit: { + reportName: 'Saved Objects Integration Tests - Serverless Env - Complete Tier', + }, +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/draft_timeline.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/tests/draft_timeline.ts similarity index 100% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/draft_timeline.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/tests/draft_timeline.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/helpers.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/tests/helpers.ts similarity index 100% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/helpers.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/tests/helpers.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/index.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/tests/index.ts similarity index 100% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/index.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/tests/index.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/notes.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/tests/notes.ts similarity index 100% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/notes.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/tests/notes.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/tests/pinned_events.ts similarity index 100% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/pinned_events.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/tests/pinned_events.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/timeline.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/tests/timeline.ts similarity index 100% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/timeline.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/tests/timeline.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/configs/ess.config.ts index 4c96f07342a58..80f9327a0c19e 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/configs/ess.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/configs/ess.config.ts @@ -20,7 +20,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { `--xpack.securitySolution.enableExperimental=${JSON.stringify([])}`, ], }, - testFiles: [require.resolve('..')], + testFiles: [require.resolve('../../tests')], junit: { reportName: 'Saved Objects Integration Tests - ESS Env - Basic License', }, diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/configs/serverless.config.ts index a5d28b90c8dc9..2bb0168b6e8ad 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/configs/serverless.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/saved_objects/trial_license_complete_tier/configs/serverless.config.ts @@ -16,7 +16,7 @@ export default createTestConfig({ { product_line: 'cloud', product_tier: 'complete' }, ])}`, ], - testFiles: [require.resolve('..')], + testFiles: [require.resolve('../../tests')], junit: { reportName: 'Saved Objects Integration Tests - Serverless Env - Complete Tier', }, diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/configs/ess.basic.config.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/basic_license_essentials_tier/configs/ess.config.ts similarity index 94% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/configs/ess.basic.config.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/basic_license_essentials_tier/configs/ess.config.ts index 279b9a1a2ed57..a1bcb8a145ad6 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/configs/ess.basic.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/basic_license_essentials_tier/configs/ess.config.ts @@ -20,7 +20,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { `--xpack.securitySolution.enableExperimental=${JSON.stringify([])}`, ], }, - testFiles: [require.resolve('../tests/basic')], + testFiles: [require.resolve('../../tests')], junit: { reportName: 'Timeline Integration Tests - ESS Env - Basic License', }, diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/basic_license_essentials_tier/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/basic_license_essentials_tier/configs/serverless.config.ts new file mode 100644 index 0000000000000..2e5fa848fb16b --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/basic_license_essentials_tier/configs/serverless.config.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../config/serverless/config.base'; + +export default createTestConfig({ + kbnTestServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify([])}`, + `--xpack.securitySolutionServerless.productTypes=${JSON.stringify([ + { product_line: 'security', product_tier: 'essentials' }, + { product_line: 'endpoint', product_tier: 'essentials' }, + { product_line: 'cloud', product_tier: 'essentials' }, + ])}`, + ], + testFiles: [require.resolve('../../tests')], + junit: { + reportName: 'Timeline Integration Tests - Serverless Env - Essentials Tier', + }, +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/mocks/timeline_details.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/mocks/timeline_details.ts similarity index 100% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/mocks/timeline_details.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/mocks/timeline_details.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/events.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/events.ts deleted file mode 100644 index a694a4cd170da..0000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/events.ts +++ /dev/null @@ -1,398 +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 { JsonObject } from '@kbn/utility-types'; -import expect from '@kbn/expect'; -import { ALERT_UUID, ALERT_RULE_CONSUMER } from '@kbn/rule-data-utils'; - -import { TimelineEdges, TimelineNonEcsData } from '@kbn/timelines-plugin/common'; -import { - Direction, - TimelineEventsQueries, -} from '@kbn/security-solution-plugin/common/search_strategy'; -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { User } from '../../../../../../../rule_registry/common/lib/authentication/types'; -import { getSpaceUrlPrefix } from '../../../../../../../rule_registry/common/lib/authentication/spaces'; - -import { - superUser, - globalRead, - obsOnly, - obsOnlyRead, - obsSec, - obsSecRead, - secOnly, - secOnlyRead, - secOnlySpace2, - secOnlyReadSpace2, - obsSecAllSpace2, - obsSecReadSpace2, - obsOnlySpace2, - obsOnlyReadSpace2, - obsOnlySpacesAll, - obsSecSpacesAll, - secOnlySpacesAll, - noKibanaPrivileges, -} from '../../../../../../../rule_registry/common/lib/authentication/users'; -import type { FtrProviderContextWithSpaces } from '../../../../../../ftr_provider_context_with_spaces'; - -interface TestCase { - /** The space where the alert exists */ - space?: string; - /** The ID of the solution for which to get alerts */ - featureIds: string[]; - /** The total alerts expected to be returned */ - expectedNumberAlerts: number; - /** body to be posted */ - body: JsonObject; - /** Authorized users */ - authorizedUsers: User[]; - /** Unauthorized users */ - unauthorizedUsers: User[]; - /** Users who are authorized for one, but not all of the alert solutions being queried */ - usersWithoutAllPrivileges?: User[]; -} - -const TO = '3000-01-01T00:00:00.000Z'; -const FROM = '2000-01-01T00:00:00.000Z'; -const TEST_URL = '/internal/search/timelineSearchStrategy/'; -const SPACE_1 = 'space1'; -const SPACE_2 = 'space2'; - -export default ({ getService }: FtrProviderContextWithSpaces) => { - const esArchiver = getService('esArchiver'); - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const getPostBody = (): JsonObject => ({ - defaultIndex: ['.alerts-*'], - entityType: 'alerts', - factoryQueryType: TimelineEventsQueries.all, - fieldRequested: ['@timestamp', 'message', ALERT_RULE_CONSUMER, ALERT_UUID, 'event.kind'], - fields: [], - filterQuery: { - bool: { - filter: [ - { - match_all: {}, - }, - ], - }, - }, - pagination: { - activePage: 0, - querySize: 25, - }, - language: 'kuery', - sort: [ - { - field: '@timestamp', - direction: Direction.desc, - type: 'number', - }, - ], - timerange: { - from: FROM, - to: TO, - interval: '12h', - }, - }); - - // TODO: Fix or update the tests - describe.skip('Timeline - Events', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); - }); - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/rule_registry/alerts'); - }); - - function addTests({ - space, - authorizedUsers, - usersWithoutAllPrivileges, - unauthorizedUsers, - body, - featureIds, - expectedNumberAlerts, - }: TestCase) { - authorizedUsers.forEach(({ username, password }) => { - it(`${username} should be able to view alerts from "${featureIds.join(',')}" ${ - space != null ? `in space ${space}` : 'when no space specified' - }`, async () => { - // This will be flake until it uses the bsearch service, but these tests aren't operational. Once you do make this operational - // use const bsearch = getService('bsearch'); - const resp = await supertestWithoutAuth - .post(`${getSpaceUrlPrefix(space)}${TEST_URL}`) - .auth(username, password) - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set('kbn-xsrf', 'true') - .set('Content-Type', 'application/json') - .send({ ...body }) - .expect(200); - - const timeline = resp.body; - - expect( - timeline.edges.every((hit: TimelineEdges) => { - const data: TimelineNonEcsData[] = hit.node.data; - return data.some(({ field, value }) => { - return ( - field === ALERT_RULE_CONSUMER && featureIds.includes((value && value[0]) ?? '') - ); - }); - }) - ).to.equal(true); - expect(timeline.totalCount).to.be(expectedNumberAlerts); - }); - }); - - if (usersWithoutAllPrivileges != null) { - usersWithoutAllPrivileges.forEach(({ username, password }) => { - it(`${username} should NOT be able to view alerts from "${featureIds.join(',')}" ${ - space != null ? `in space ${space}` : 'when no space specified' - }`, async () => { - // This will be flake until it uses the bsearch service, but these tests aren't operational. Once you do make this operational - // use const bsearch = getService('bsearch'); - const resp = await supertestWithoutAuth - .post(`${getSpaceUrlPrefix(space)}${TEST_URL}`) - .auth(username, password) - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set('kbn-xsrf', 'true') - .set('Content-Type', 'application/json') - .send({ ...body }) - .expect(200); - - const timeline = resp.body; - - expect(timeline.totalCount).to.be(0); - }); - }); - } - - unauthorizedUsers.forEach(({ username, password }) => { - it(`${username} should NOT be able to access "${featureIds.join(',')}" ${ - space != null ? `in space ${space}` : 'when no space specified' - }`, async () => { - // This will be flake until it uses the bsearch service, but these tests aren't operational. Once you do make this operational - // use const bsearch = getService('bsearch'); - await supertestWithoutAuth - .post(`${getSpaceUrlPrefix(space)}${TEST_URL}`) - .auth(username, password) - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set('kbn-xsrf', 'true') - .set('Content-Type', 'application/json') - .send({ ...body }) - // TODO - This should be updated to be a 403 once this ticket is resolved - // https://github.com/elastic/kibana/issues/106005 - .expect(500); - }); - }); - } - - describe('alerts authentication', () => { - const authorizedSecSpace1 = [secOnly, secOnlyRead]; - const authorizedObsSpace1 = [obsOnly, obsOnlyRead]; - const authorizedSecObsSpace1 = [obsSec, obsSecRead]; - - const authorizedSecSpace2 = [secOnlySpace2, secOnlyReadSpace2]; - const authorizedObsSpace2 = [obsOnlySpace2, obsOnlyReadSpace2]; - const authorizedSecObsSpace2 = [obsSecAllSpace2, obsSecReadSpace2]; - - const authorizedSecInAllSpaces = [secOnlySpacesAll]; - const authorizedObsInAllSpaces = [obsOnlySpacesAll]; - const authorizedSecObsInAllSpaces = [obsSecSpacesAll]; - - const authorizedInAllSpaces = [superUser, globalRead]; - const unauthorized = [noKibanaPrivileges]; - - describe('Querying for Security Solution alerts only', () => { - addTests({ - space: SPACE_1, - featureIds: ['siem'], - expectedNumberAlerts: 2, - body: { - ...getPostBody(), - defaultIndex: ['.alerts-*'], - entityType: 'alerts', - alertConsumers: ['siem'], - }, - authorizedUsers: [ - ...authorizedSecSpace1, - ...authorizedSecObsSpace1, - ...authorizedSecInAllSpaces, - ...authorizedSecObsInAllSpaces, - ...authorizedInAllSpaces, - ], - usersWithoutAllPrivileges: [...authorizedObsSpace1, ...authorizedObsInAllSpaces], - unauthorizedUsers: [ - ...authorizedSecSpace2, - ...authorizedObsSpace2, - ...authorizedSecObsSpace2, - ...unauthorized, - ], - }); - - addTests({ - space: SPACE_2, - featureIds: ['siem'], - expectedNumberAlerts: 2, - body: { - ...getPostBody(), - alertConsumers: ['siem'], - }, - authorizedUsers: [ - ...authorizedSecSpace2, - ...authorizedSecObsSpace2, - ...authorizedSecInAllSpaces, - ...authorizedSecObsInAllSpaces, - ...authorizedInAllSpaces, - ], - usersWithoutAllPrivileges: [...authorizedObsSpace2, ...authorizedObsInAllSpaces], - unauthorizedUsers: [ - ...authorizedSecSpace1, - ...authorizedObsSpace1, - ...authorizedSecObsSpace1, - ...unauthorized, - ], - }); - }); - - describe('Querying for APM alerts only', () => { - addTests({ - space: SPACE_1, - featureIds: ['apm'], - expectedNumberAlerts: 2, - body: { - ...getPostBody(), - alertConsumers: ['apm'], - }, - authorizedUsers: [ - ...authorizedObsSpace1, - ...authorizedSecObsSpace1, - ...authorizedObsInAllSpaces, - ...authorizedSecObsInAllSpaces, - ...authorizedInAllSpaces, - ], - usersWithoutAllPrivileges: [...authorizedSecSpace1, ...authorizedSecInAllSpaces], - unauthorizedUsers: [ - ...authorizedSecSpace2, - ...authorizedObsSpace2, - ...authorizedSecObsSpace2, - ...unauthorized, - ], - }); - addTests({ - space: SPACE_2, - featureIds: ['apm'], - expectedNumberAlerts: 2, - body: { - ...getPostBody(), - alertConsumers: ['apm'], - }, - authorizedUsers: [ - ...authorizedObsSpace2, - ...authorizedSecObsSpace2, - ...authorizedObsInAllSpaces, - ...authorizedSecObsInAllSpaces, - ...authorizedInAllSpaces, - ], - usersWithoutAllPrivileges: [...authorizedSecSpace2, ...authorizedSecInAllSpaces], - unauthorizedUsers: [ - ...authorizedSecSpace1, - ...authorizedObsSpace1, - ...authorizedSecObsSpace1, - ...unauthorized, - ], - }); - }); - - describe('Querying for multiple solutions', () => { - describe('authorized for both security solution and apm', () => { - addTests({ - space: SPACE_1, - featureIds: ['siem', 'apm'], - expectedNumberAlerts: 4, - body: { - ...getPostBody(), - defaultIndex: ['.alerts-*'], - entityType: 'alerts', - alertConsumers: ['siem', 'apm'], - }, - authorizedUsers: [ - ...authorizedSecObsSpace1, - ...authorizedSecObsInAllSpaces, - ...authorizedInAllSpaces, - ], - unauthorizedUsers: [...unauthorized], - }); - addTests({ - space: SPACE_2, - featureIds: ['siem', 'apm'], - expectedNumberAlerts: 4, - body: { - ...getPostBody(), - defaultIndex: ['.alerts-*'], - entityType: 'alerts', - alertConsumers: ['siem', 'apm'], - }, - authorizedUsers: [ - ...authorizedSecObsSpace2, - ...authorizedSecObsInAllSpaces, - ...authorizedInAllSpaces, - ], - unauthorizedUsers: [...unauthorized], - }); - }); - describe('security solution privileges only', () => { - addTests({ - space: SPACE_1, - featureIds: ['siem'], - expectedNumberAlerts: 2, - body: { - ...getPostBody(), - defaultIndex: ['.alerts-*'], - entityType: 'alerts', - alertConsumers: ['siem', 'apm'], - }, - authorizedUsers: [...authorizedSecInAllSpaces], - unauthorizedUsers: [...unauthorized], - }); - }); - - describe('apm privileges only', () => { - addTests({ - space: SPACE_1, - featureIds: ['apm'], - expectedNumberAlerts: 2, - body: { - ...getPostBody(), - defaultIndex: ['.alerts-*'], - entityType: 'alerts', - alertConsumers: ['siem', 'apm'], - }, - authorizedUsers: [...authorizedObsInAllSpaces], - unauthorizedUsers: [...unauthorized], - }); - }); - - describe('querying from default space when no alerts were created in default space', () => { - addTests({ - featureIds: ['siem'], - expectedNumberAlerts: 0, - body: { - ...getPostBody(), - defaultIndex: ['.alerts-*'], - entityType: 'alerts', - alertConsumers: ['siem', 'apm'], - }, - authorizedUsers: [...authorizedSecInAllSpaces], - unauthorizedUsers: [...unauthorized], - }); - }); - }); - }); - }); -}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/index.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/index.ts deleted file mode 100644 index 809e6d7cba75b..0000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/index.ts +++ /dev/null @@ -1,29 +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 { FtrProviderContextWithSpaces } from '../../../../../../ftr_provider_context_with_spaces'; -import { - createSpacesAndUsers, - deleteSpacesAndUsers, -} from '../../../../../../../rule_registry/common/lib/authentication'; - -export default ({ loadTestFile, getService }: FtrProviderContextWithSpaces): void => { - describe('@ess timeline security and spaces enabled: basic', function () { - before(async () => { - await createSpacesAndUsers(getService); - }); - - after(async () => { - await deleteSpacesAndUsers(getService); - }); - - // Basic - loadTestFile(require.resolve('./events')); - loadTestFile(require.resolve('./import_timelines')); - loadTestFile(require.resolve('./install_prepackaged_timelines')); - }); -}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/trial/events.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/trial/events.ts deleted file mode 100644 index 6ff03cc9b2cc2..0000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/trial/events.ts +++ /dev/null @@ -1,279 +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 Path from 'path'; -import Fs from 'fs'; -import { JsonObject } from '@kbn/utility-types'; -import expect from '@kbn/expect'; -import { ALERT_RULE_CONSUMER } from '@kbn/rule-data-utils'; - -import { TimelineEdges, TimelineNonEcsData } from '@kbn/timelines-plugin/common'; -import { - Direction, - TimelineEventsQueries, -} from '@kbn/security-solution-plugin/common/search_strategy'; -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { User } from '../../../../../../../rule_registry/common/lib/authentication/types'; -import { getSpaceUrlPrefix } from '../../../../../../../rule_registry/common/lib/authentication/spaces'; - -import { - obsMinReadAlertsRead, - obsMinReadAlertsReadSpacesAll, - obsMinRead, - obsMinReadSpacesAll, - superUser, -} from '../../../../../../../rule_registry/common/lib/authentication/users'; -import { FtrProviderContextWithSpaces } from '../../../../../../ftr_provider_context_with_spaces'; - -class FileWrapper { - constructor(private readonly path: string) {} - async reset() { - // "touch" each file to ensure it exists and is empty before each test - await Fs.promises.writeFile(this.path, ''); - } - async read() { - const content = await Fs.promises.readFile(this.path, { encoding: 'utf8' }); - return content.trim().split('\n'); - } - async readJSON() { - const content = await this.read(); - return content.map((l) => JSON.parse(l)); - } - // writing in a file is an async operation. we use this method to make sure logs have been written. - async isNotEmpty() { - const content = await this.read(); - const line = content[0]; - return line.length > 0; - } -} - -interface TestCase { - /** The space where the alert exists */ - space?: string; - /** The ID of the solution for which to get alerts */ - featureIds: string[]; - /** The total alerts expected to be returned */ - expectedNumberAlerts: number; - /** body to be posted */ - body: JsonObject; - /** Authorized users */ - authorizedUsers: User[]; - /** Unauthorized users */ - unauthorizedUsers: User[]; -} - -const TO = '3000-01-01T00:00:00.000Z'; -const FROM = '2000-01-01T00:00:00.000Z'; -const TEST_URL = '/internal/search/timelineSearchStrategy/'; -const SPACE_1 = 'space1'; -const SPACE_2 = 'space2'; - -export default ({ getService }: FtrProviderContextWithSpaces) => { - const esArchiver = getService('esArchiver'); - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const getPostBody = (): JsonObject => ({ - defaultIndex: ['.alerts-*'], - entityType: 'alerts', - factoryQueryType: TimelineEventsQueries.all, - fieldRequested: ['@timestamp'], - fields: [], - filterQuery: { - bool: { - filter: [ - { - match_all: {}, - }, - ], - }, - }, - pagination: { - activePage: 0, - querySize: 25, - }, - language: 'kuery', - sort: [ - { - field: '@timestamp', - direction: Direction.desc, - type: 'number', - }, - ], - timerange: { - from: FROM, - to: TO, - interval: '12h', - }, - }); - - // TODO: Fix or update the tests - describe.skip('Timeline - Events', () => { - const logFilePath = Path.resolve(__dirname, '../../../common/audit.log'); - const logFile = new FileWrapper(logFilePath); - const retry = getService('retry'); - - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); - }); - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/rule_registry/alerts'); - }); - - function addTests({ - space, - authorizedUsers, - unauthorizedUsers, - body, - featureIds, - expectedNumberAlerts, - }: TestCase) { - authorizedUsers.forEach(({ username, password }) => { - it(`${username} should be able to view alerts from "${featureIds.join(',')}" ${ - space != null ? `in space ${space}` : 'when no space specified' - }`, async () => { - // This will be flake until it uses the bsearch service, but these tests aren't operational. Once you do make this operational - // use const bsearch = getService('bsearch'); - const resp = await supertestWithoutAuth - .post(`${getSpaceUrlPrefix(space)}${TEST_URL}`) - .auth(username, password) - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set('kbn-xsrf', 'true') - .set('Content-Type', 'application/json') - .send({ ...body }) - .expect(200); - - const timeline = resp.body; - - expect( - timeline.edges.every((hit: TimelineEdges) => { - const data: TimelineNonEcsData[] = hit.node.data; - return data.some(({ field, value }) => { - return ( - field === ALERT_RULE_CONSUMER && featureIds.includes((value && value[0]) ?? '') - ); - }); - }) - ).to.equal(true); - expect(timeline.totalCount).to.be(expectedNumberAlerts); - }); - }); - - unauthorizedUsers.forEach(({ username, password }) => { - it(`${username} should NOT be able to access "${featureIds.join(',')}" ${ - space != null ? `in space ${space}` : 'when no space specified' - }`, async () => { - // This will be flake until it uses the bsearch service, but these tests aren't operational. Once you do make this operational - // use const bsearch = getService('bsearch'); - await supertestWithoutAuth - .post(`${getSpaceUrlPrefix(space)}${TEST_URL}`) - .auth(username, password) - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set('kbn-xsrf', 'true') - .set('Content-Type', 'application/json') - .send({ ...body }) - // TODO - This should be updated to be a 403 once this ticket is resolved - // https://github.com/elastic/kibana/issues/106005 - .expect(500); - }); - }); - } - - // TODO - tests need to be updated with new table logic - describe('alerts authentication', () => { - addTests({ - space: SPACE_1, - featureIds: ['apm'], - expectedNumberAlerts: 2, - body: { - ...getPostBody(), - defaultIndex: ['.alerts*'], - entityType: 'alerts', - alertConsumers: ['apm'], - }, - authorizedUsers: [obsMinReadAlertsRead, obsMinReadAlertsReadSpacesAll], - unauthorizedUsers: [obsMinRead, obsMinReadSpacesAll], - }); - }); - - // FLAKY: https://github.com/elastic/kibana/issues/117462 - describe('logging', () => { - beforeEach(async () => { - await logFile.reset(); - }); - - afterEach(async () => { - await logFile.reset(); - }); - - it('logs success events when reading alerts', async () => { - await supertestWithoutAuth - .post(`${getSpaceUrlPrefix(SPACE_1)}${TEST_URL}`) - .auth(superUser.username, superUser.password) - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set('kbn-xsrf', 'true') - .set('Content-Type', 'application/json') - .send({ - ...getPostBody(), - defaultIndex: ['.alerts-*'], - entityType: 'alerts', - alertConsumers: ['apm'], - }) - .expect(200); - await retry.waitFor('logs event in the dest file', async () => await logFile.isNotEmpty()); - - const content = await logFile.readJSON(); - - const httpEvent = content.find((c) => c.event.action === 'http_request'); - expect(httpEvent).to.be.ok(); - expect(httpEvent.trace.id).to.be.ok(); - expect(httpEvent.user.name).to.be(superUser.username); - expect(httpEvent.kibana.space_id).to.be('space1'); - expect(httpEvent.http.request.method).to.be('post'); - expect(httpEvent.url.path).to.be('/s/space1/internal/search/timelineSearchStrategy/'); - - const findEvents = content.filter((c) => c.event.action === 'alert_find'); - expect(findEvents[0].trace.id).to.be.ok(); - expect(findEvents[0].event.outcome).to.be('success'); - expect(findEvents[0].user.name).to.be(superUser.username); - expect(findEvents[0].kibana.space_id).to.be('space1'); - }); - - it('logs failure events when unauthorized to read alerts', async () => { - await supertestWithoutAuth - .post(`${getSpaceUrlPrefix(SPACE_2)}${TEST_URL}`) - .auth(obsMinRead.username, obsMinRead.password) - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set('kbn-xsrf', 'true') - .set('Content-Type', 'application/json') - .send({ - ...getPostBody(), - defaultIndex: ['.alerts-*'], - entityType: 'alerts', - alertConsumers: ['apm'], - }) - .expect(500); - await retry.waitFor('logs event in the dest file', async () => await logFile.isNotEmpty()); - - const content = await logFile.readJSON(); - - const httpEvent = content.find((c) => c.event.action === 'http_request'); - expect(httpEvent).to.be.ok(); - expect(httpEvent.trace.id).to.be.ok(); - expect(httpEvent.user.name).to.be(obsMinRead.username); - expect(httpEvent.kibana.space_id).to.be(SPACE_2); - expect(httpEvent.http.request.method).to.be('post'); - expect(httpEvent.url.path).to.be('/s/space2/internal/search/timelineSearchStrategy/'); - - const findEvents = content.filter((c) => c.event.action === 'alert_find'); - expect(findEvents.length).to.equal(1); - expect(findEvents[0].trace.id).to.be.ok(); - expect(findEvents[0].event.outcome).to.be('failure'); - expect(findEvents[0].user.name).to.be(obsMinRead.username); - expect(findEvents[0].kibana.space_id).to.be(SPACE_2); - }); - }); - }); -}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/trial/index.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/trial/index.ts deleted file mode 100644 index 381d3a5b657bb..0000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/trial/index.ts +++ /dev/null @@ -1,99 +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 type { FtrProviderContextWithSpaces } from '../../../../../../ftr_provider_context_with_spaces'; -import { - createSpaces, - createUsersAndRoles, - deleteSpaces, - deleteUsersAndRoles, -} from '../../../../../../../rule_registry/common/lib/authentication'; - -import { - observabilityMinReadAlertsRead, - observabilityMinReadAlertsReadSpacesAll, - observabilityMinimalRead, - observabilityMinimalReadSpacesAll, - observabilityMinReadAlertsAll, - observabilityMinReadAlertsAllSpacesAll, - observabilityMinimalAll, - observabilityMinimalAllSpacesAll, -} from '../../../../../../../rule_registry/common/lib/authentication/roles'; -import { - obsMinReadAlertsRead, - obsMinReadAlertsReadSpacesAll, - obsMinRead, - obsMinReadSpacesAll, - superUser, - obsMinReadAlertsAll, - obsMinReadAlertsAllSpacesAll, - obsMinAll, - obsMinAllSpacesAll, -} from '../../../../../../../rule_registry/common/lib/authentication/users'; - -export default ({ loadTestFile, getService }: FtrProviderContextWithSpaces): void => { - describe('@ess timeline security and spaces enabled: trial', function () { - before(async () => { - await createSpaces(getService); - await createUsersAndRoles( - getService, - [ - obsMinReadAlertsRead, - obsMinReadAlertsReadSpacesAll, - obsMinRead, - obsMinReadSpacesAll, - superUser, - obsMinReadAlertsAll, - obsMinReadAlertsAllSpacesAll, - obsMinAll, - obsMinAllSpacesAll, - ], - [ - observabilityMinReadAlertsRead, - observabilityMinReadAlertsReadSpacesAll, - observabilityMinimalRead, - observabilityMinimalReadSpacesAll, - observabilityMinReadAlertsAll, - observabilityMinReadAlertsAllSpacesAll, - observabilityMinimalAll, - observabilityMinimalAllSpacesAll, - ] - ); - }); - - after(async () => { - await deleteSpaces(getService); - await deleteUsersAndRoles( - getService, - [ - obsMinReadAlertsRead, - obsMinReadAlertsReadSpacesAll, - obsMinRead, - obsMinReadSpacesAll, - superUser, - obsMinReadAlertsAll, - obsMinReadAlertsAllSpacesAll, - obsMinAll, - obsMinAllSpacesAll, - ], - [ - observabilityMinReadAlertsRead, - observabilityMinReadAlertsReadSpacesAll, - observabilityMinimalRead, - observabilityMinimalReadSpacesAll, - observabilityMinReadAlertsAll, - observabilityMinReadAlertsAllSpacesAll, - observabilityMinimalAll, - observabilityMinimalAllSpacesAll, - ] - ); - }); - - // Trial - loadTestFile(require.resolve('./events')); - }); -}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/events.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/events.ts similarity index 94% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/events.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/events.ts index c42ac64de4a23..9db1a5dfceb22 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/events.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/events.ts @@ -15,9 +15,9 @@ import { } from '@kbn/security-solution-plugin/common/search_strategy'; import TestAgent from 'supertest/lib/agent'; import { BsearchService } from '@kbn/ftr-common-functional-services'; -import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; +import { FtrProviderContextWithSpaces } from '../../../../ftr_provider_context_with_spaces'; -import { getFieldsToRequest, getFilterValue } from '../../../../utils'; +import { getFieldsToRequest, getFilterValue } from '../../../utils'; const TO = '3000-01-01T00:00:00.000Z'; const FROM = '2000-01-01T00:00:00.000Z'; @@ -60,7 +60,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { }, }); - describe('Timeline', () => { + describe('@skipInServerless Timeline', () => { let supertest: TestAgent; let bsearch: BsearchService; diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/import_timelines.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/import_timelines.ts similarity index 98% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/import_timelines.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/import_timelines.ts index 455780b333c8f..90f56e82a310a 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/import_timelines.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/import_timelines.ts @@ -9,8 +9,8 @@ import expect from '@kbn/expect'; import { TIMELINE_IMPORT_URL } from '@kbn/security-solution-plugin/common/constants'; -import { FtrProviderContextWithSpaces } from '../../../../../../ftr_provider_context_with_spaces'; -import { deleteAllTimelines } from '../../../utils'; +import { FtrProviderContextWithSpaces } from '../../../../ftr_provider_context_with_spaces'; +import { deleteAllTimelines } from '../utils'; export default ({ getService }: FtrProviderContextWithSpaces): void => { const supertest = getService('supertest'); diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/index.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/index.ts similarity index 65% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/index.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/index.ts index ebf592d01282b..0d14c693ea828 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/index.ts @@ -5,14 +5,15 @@ * 2.0. */ -import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; +import { FtrProviderContextWithSpaces } from '../../../../ftr_provider_context_with_spaces'; export default function ({ loadTestFile }: FtrProviderContextWithSpaces) { - // Failed in serverless: https://github.com/elastic/kibana/issues/183645 - describe('@ess @serverless @skipInServerless SecuritySolution Timeline', () => { + describe('@ess @serverless SecuritySolution Timeline', () => { loadTestFile(require.resolve('./events')); loadTestFile(require.resolve('./timeline_details')); loadTestFile(require.resolve('./timeline')); loadTestFile(require.resolve('./timeline_migrations')); + loadTestFile(require.resolve('./import_timelines')); + loadTestFile(require.resolve('./install_prepackaged_timelines')); }); } diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/install_prepackaged_timelines.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/install_prepackaged_timelines.ts similarity index 63% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/install_prepackaged_timelines.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/install_prepackaged_timelines.ts index 3e85d2a85c399..58c9442b12159 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/security_and_spaces/tests/basic/install_prepackaged_timelines.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/install_prepackaged_timelines.ts @@ -8,13 +8,12 @@ import expect from '@kbn/expect'; import { TIMELINE_PREPACKAGED_URL } from '@kbn/security-solution-plugin/common/constants'; -import { FtrProviderContextWithSpaces } from '../../../../../../ftr_provider_context_with_spaces'; -import { deleteAllTimelines, waitFor } from '../../../utils'; +import { FtrProviderContextWithSpaces } from '../../../../ftr_provider_context_with_spaces'; +import { deleteAllTimelines } from '../utils'; export default ({ getService }: FtrProviderContextWithSpaces): void => { const supertest = getService('supertest'); const es = getService('es'); - const log = getService('log'); describe('install_prepackaged_timelines', () => { describe('creating prepackaged rules', () => { @@ -22,15 +21,27 @@ export default ({ getService }: FtrProviderContextWithSpaces): void => { await deleteAllTimelines(es); }); - // TODO: Fix or update the tests - it.skip('should contain timelines_installed, and timelines_updated', async () => { + it('should contain timelines_installed, and timelines_updated', async () => { const { body } = await supertest .post(TIMELINE_PREPACKAGED_URL) .set('kbn-xsrf', 'true') .send() .expect(200); - expect(Object.keys(body)).to.eql(['timelines_installed', 'timelines_updated']); + expect(Object.keys(body)).to.eql([ + 'success', + 'success_count', + 'timelines_installed', + 'timelines_updated', + 'errors', + ]); + expect(body).to.eql({ + success: true, + success_count: 10, + errors: [], + timelines_installed: 10, + timelines_updated: 0, + }); }); it('should create the prepackaged timelines and return a count greater than zero', async () => { @@ -53,29 +64,16 @@ export default ({ getService }: FtrProviderContextWithSpaces): void => { expect(body.timelines_updated).to.eql(0); }); - // TODO: Fix or update the tests - it.skip('should be possible to call the API twice and the second time the number of timelines installed should be zero', async () => { + it('should be possible to call the API twice and the second time the number of timelines installed should be zero', async () => { await supertest.post(TIMELINE_PREPACKAGED_URL).set('kbn-xsrf', 'true').send().expect(200); - await waitFor( - async () => { - const { body } = await supertest - .get(`${TIMELINE_PREPACKAGED_URL}/_status`) - .set('kbn-xsrf', 'true') - .expect(200); - return body.timelines_not_installed === 0; - }, - `${TIMELINE_PREPACKAGED_URL}/_status`, - log - ); - - const { body } = await supertest + const { body: timelinePrepackagedResponseBody } = await supertest .post(TIMELINE_PREPACKAGED_URL) .set('kbn-xsrf', 'true') .send() .expect(200); - expect(body.timelines_installed).to.eql(0); + expect(timelinePrepackagedResponseBody.timelines_installed).to.eql(0); }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline.ts similarity index 93% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline.ts index 8a37ad6e9cac9..db5abd723f6f6 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline.ts @@ -8,11 +8,11 @@ import expect from '@kbn/expect'; import { SavedTimeline, TimelineTypeEnum } from '@kbn/security-solution-plugin/common/api/timeline'; -import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; +import { FtrProviderContextWithSpaces } from '../../../../ftr_provider_context_with_spaces'; import { createBasicTimeline, createBasicTimelineTemplate, -} from '../../../saved_objects/trial_license_complete_tier/helpers'; +} from '../../saved_objects/tests/helpers'; export default function ({ getService }: FtrProviderContextWithSpaces) { const supertest = getService('supertest'); @@ -60,7 +60,11 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { ).to.equal(0); }); }); - describe('resolve timeline', () => { + /** + * Migration of saved object not working to current serverless version + * https://github.com/elastic/kibana/issues/196483 + * */ + describe.skip('resolve timeline', () => { before(async () => { await esArchiver.load( 'x-pack/test/functional/es_archives/security_solution/timelines/7.15.0' diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline_details.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_details.ts similarity index 94% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline_details.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_details.ts index 12539d43a145f..7d127ab7c0f96 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline_details.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_details.ts @@ -15,7 +15,7 @@ import { import TestAgent from 'supertest/lib/agent'; import { BsearchService } from '@kbn/ftr-common-functional-services'; -import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; +import { FtrProviderContextWithSpaces } from '../../../../ftr_provider_context_with_spaces'; import { timelineDetailsFilebeatExpectedResults as EXPECTED_DATA } from '../mocks/timeline_details'; // typical values that have to change after an update from "scripts/es_archiver" @@ -34,7 +34,7 @@ export default function ({ getService }: FtrProviderContextWithSpaces) { const esArchiver = getService('esArchiver'); const utils = getService('securitySolutionUtils'); - describe('Timeline Details', () => { + describe('@skipInServerless Timeline Details', () => { let supertest: TestAgent; let bsearch: BsearchService; before(async () => { diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline_migrations.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_migrations.ts similarity index 97% rename from x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline_migrations.ts rename to x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_migrations.ts index c91d4ce24ce51..4aafce9938ae1 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/tests/timeline_migrations.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_migrations.ts @@ -16,8 +16,8 @@ import { BarePinnedEventWithoutExternalRefs, TimelineWithoutExternalRefs, } from '@kbn/security-solution-plugin/common/api/timeline'; -import type { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; -import { getSavedObjectFromES } from '../../../../utils'; +import type { FtrProviderContextWithSpaces } from '../../../../ftr_provider_context_with_spaces'; +import { getSavedObjectFromES } from '../../../utils'; interface TimelineWithoutSavedQueryId { [timelineSavedObjectType]: TimelineWithoutExternalRefs; @@ -34,7 +34,7 @@ interface PinnedEventWithoutTimelineId { export default function ({ getService }: FtrProviderContextWithSpaces) { const supertest = getService('supertest'); - describe('Timeline migrations', () => { + describe('@skipInServerless Timeline migrations', () => { const esArchiver = getService('esArchiver'); const es = getService('es'); const kibanaServer = getService('kibanaServer'); diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/configs/ess.config.ts index 8fd44a2a2c5d9..8d9c8ad8a4652 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/configs/ess.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/configs/ess.config.ts @@ -20,7 +20,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { `--xpack.securitySolution.enableExperimental=${JSON.stringify([])}`, ], }, - testFiles: [require.resolve('../tests')], + testFiles: [require.resolve('../../tests')], junit: { reportName: 'Timeline Integration Tests - ESS Env - Trial License', }, diff --git a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/configs/serverless.config.ts index 0a2827db15d66..0f8a8a350c3ed 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/configs/serverless.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/trial_license_complete_tier/configs/serverless.config.ts @@ -16,7 +16,7 @@ export default createTestConfig({ { product_line: 'cloud', product_tier: 'complete' }, ])}`, ], - testFiles: [require.resolve('../tests')], + testFiles: [require.resolve('../../tests')], junit: { reportName: 'Timeline Integration Tests - Serverless Env - Complete Tier', }, diff --git a/x-pack/test/security_solution_api_integration/tsconfig.json b/x-pack/test/security_solution_api_integration/tsconfig.json index 82decfa5a6db3..b7a320dd19720 100644 --- a/x-pack/test/security_solution_api_integration/tsconfig.json +++ b/x-pack/test/security_solution_api_integration/tsconfig.json @@ -45,7 +45,6 @@ "@kbn/actions-plugin", "@kbn/task-manager-plugin", "@kbn/utility-types", - "@kbn/timelines-plugin", "@kbn/dev-cli-runner", "@kbn/elastic-assistant-common", "@kbn/search-types", From 6438520c6522263bd38bf68606cf36fce4ce9697 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Wed, 16 Oct 2024 12:31:32 -0600 Subject: [PATCH 26/30] [Security assistant] Fix `AlertsRange` for Assistant (#196582) --- .../assistant/settings/alerts_settings/alerts_settings.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings.tsx index 3b48c8d0861c5..57ad1312a271e 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/alerts_settings/alerts_settings.tsx @@ -13,9 +13,9 @@ import { KnowledgeBaseConfig } from '../../types'; import { AlertsRange } from '../../../knowledge_base/alerts_range'; import * as i18n from '../../../knowledge_base/translations'; -export const MIN_LATEST_ALERTS = 10; -export const MAX_LATEST_ALERTS = 100; -export const TICK_INTERVAL = 10; +export const MIN_LATEST_ALERTS = 50; +export const MAX_LATEST_ALERTS = 500; +export const TICK_INTERVAL = 50; export const RANGE_CONTAINER_WIDTH = 600; // px const LABEL_WRAPPER_MIN_WIDTH = 95; // px From 708bf08f91502a501f9744a4a0b35c6cbdeb9990 Mon Sep 17 00:00:00 2001 From: Joe McElroy Date: Wed, 16 Oct 2024 19:50:33 +0100 Subject: [PATCH 27/30] [Onboarding] fix skipped api key tests (#195911) ## Summary Failing due to api keys could not be generated as keys were created previously and were purged in session. Fix is to move the deletion to run at beforeEach rather than the start. - [ ] [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 - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed --------- Co-authored-by: Elastic Machine --- .../test_suites/search/elasticsearch_start.ts | 8 +++----- .../test_suites/search/search_index_detail.ts | 15 ++++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts b/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts index d9d4389d4d63c..129f769283b34 100644 --- a/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts +++ b/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts @@ -30,13 +30,13 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('developer', function () { before(async () => { await pageObjects.svlCommonPage.loginWithRole('developer'); - await pageObjects.svlApiKeys.deleteAPIKeys(); }); after(async () => { await deleteAllTestIndices(); }); beforeEach(async () => { await deleteAllTestIndices(); + await pageObjects.svlApiKeys.deleteAPIKeys(); await svlSearchNavigation.navigateToElasticsearchStartPage(); }); @@ -92,8 +92,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.svlSearchElasticsearchStartPage.expectCreateIndexUIView(); }); - // Failing: See https://github.com/elastic/kibana/issues/194673 - it.skip('should show the api key in code view', async () => { + it('should show the api key in code view', async () => { await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage(); await pageObjects.svlSearchElasticsearchStartPage.clickCodeViewButton(); await pageObjects.svlApiKeys.expectAPIKeyAvailable(); @@ -131,8 +130,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.svlApiKeys.expectAPIKeyAvailable(); }); - // Failing: See https://github.com/elastic/kibana/issues/194673 - it.skip('Same API Key should be present on start page and index detail view', async () => { + it('Same API Key should be present on start page and index detail view', async () => { await pageObjects.svlSearchElasticsearchStartPage.clickCodeViewButton(); await pageObjects.svlApiKeys.expectAPIKeyAvailable(); const apiKeyUI = await pageObjects.svlApiKeys.getAPIKeyFromUI(); diff --git a/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts b/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts index aea757f7edea1..1cae648601d49 100644 --- a/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts +++ b/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts @@ -53,6 +53,14 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.svlSearchIndexDetailPage.expectConnectionDetails(); }); + it('should show api key', async () => { + await pageObjects.svlApiKeys.deleteAPIKeys(); + await svlSearchNavigation.navigateToIndexDetailPage(indexName); + await pageObjects.svlApiKeys.expectAPIKeyAvailable(); + const apiKey = await pageObjects.svlApiKeys.getAPIKeyFromUI(); + await pageObjects.svlSearchIndexDetailPage.expectAPIKeyToBeVisibleInCodeBlock(apiKey); + }); + it('should have quick stats', async () => { await pageObjects.svlSearchIndexDetailPage.expectQuickStats(); await pageObjects.svlSearchIndexDetailPage.expectQuickStatsAIMappings(); @@ -89,13 +97,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.embeddedConsole.clickEmbeddedConsoleControlBar(); }); - // Failing: See https://github.com/elastic/kibana/issues/194673 - it.skip('should show api key', async () => { - await pageObjects.svlApiKeys.expectAPIKeyAvailable(); - const apiKey = await pageObjects.svlApiKeys.getAPIKeyFromUI(); - await pageObjects.svlSearchIndexDetailPage.expectAPIKeyToBeVisibleInCodeBlock(apiKey); - }); - describe('With data', () => { before(async () => { await es.index({ From 888b904c4b2e905782a97b447a534891abf96bf3 Mon Sep 17 00:00:00 2001 From: seanrathier Date: Wed, 16 Oct 2024 14:59:02 -0400 Subject: [PATCH 28/30] [Cloud Security] Remove the pre-configuration check for supports_agentless (#196566) --- .../server/services/preconfiguration.test.ts | 110 ------------------ .../fleet/server/services/preconfiguration.ts | 13 --- .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 5 files changed, 126 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts index 36b6d4fdbeb17..fb2153ff903f0 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts @@ -902,116 +902,6 @@ describe('policy preconfiguration', () => { ); }); - it('should return a non fatal error if support_agentless is defined in stateful', async () => { - const soClient = getPutPreconfiguredPackagesMock(); - const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - jest.mocked(appContextService).getInternalUserSOClientForSpaceId.mockReturnValue(soClient); - jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({ - agentless: true, - } as any); - - jest - .spyOn(appContextService, 'getCloud') - .mockReturnValue({ isServerlessEnabled: false } as any); - - const policies: PreconfiguredAgentPolicy[] = [ - { - name: 'Test policy', - namespace: 'default', - id: 'test-id', - supports_agentless: true, - package_policies: [], - }, - ]; - - const { nonFatalErrors } = await ensurePreconfiguredPackagesAndPolicies( - soClient, - esClient, - policies, - [{ name: 'CANNOT_MATCH', version: 'x.y.z' }], - mockDefaultOutput, - mockDefaultDownloadService, - DEFAULT_SPACE_ID - ); - // @ts-ignore-next-line - expect(nonFatalErrors[0].error.toString()).toEqual( - 'FleetError: `supports_agentless` is only allowed in serverless environments that support the agentless feature' - ); - }); - - it('should not return an error if support_agentless is defined in serverless and agentless is enabled', async () => { - const soClient = getPutPreconfiguredPackagesMock(); - const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - jest.mocked(appContextService).getInternalUserSOClientForSpaceId.mockReturnValue(soClient); - jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({ - agentless: true, - } as any); - - jest - .spyOn(appContextService, 'getCloud') - .mockReturnValue({ isServerlessEnabled: true } as any); - - const policies: PreconfiguredAgentPolicy[] = [ - { - name: 'Test policy', - namespace: 'default', - id: 'test-id', - supports_agentless: true, - package_policies: [], - }, - ]; - - const { policies: resPolicies, nonFatalErrors } = - await ensurePreconfiguredPackagesAndPolicies( - soClient, - esClient, - policies, - [{ name: 'CANNOT_MATCH', version: 'x.y.z' }], - mockDefaultOutput, - mockDefaultDownloadService, - DEFAULT_SPACE_ID - ); - expect(nonFatalErrors.length).toBe(0); - expect(resPolicies[0].id).toEqual('test-id'); - }); - - it('should return an error if agentless feature flag is disabled on serverless', async () => { - const soClient = getPutPreconfiguredPackagesMock(); - const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - jest.mocked(appContextService).getInternalUserSOClientForSpaceId.mockReturnValue(soClient); - jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({ - agentless: false, - } as any); - - jest - .spyOn(appContextService, 'getCloud') - .mockReturnValue({ isServerlessEnabled: true } as any); - - const policies: PreconfiguredAgentPolicy[] = [ - { - name: 'Test policy', - namespace: 'default', - id: 'test-id', - supports_agentless: true, - package_policies: [], - }, - ]; - - const { nonFatalErrors } = await ensurePreconfiguredPackagesAndPolicies( - soClient, - esClient, - policies, - [{ name: 'CANNOT_MATCH', version: 'x.y.z' }], - mockDefaultOutput, - mockDefaultDownloadService, - DEFAULT_SPACE_ID - ); - // @ts-ignore-next-line - expect(nonFatalErrors[0].error.toString()).toEqual( - 'FleetError: `supports_agentless` is only allowed in serverless environments that support the agentless feature' - ); - }); - it('should not attempt to recreate or modify an agent policy if its ID is unchanged', async () => { const soClient = getPutPreconfiguredPackagesMock(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.ts b/x-pack/plugins/fleet/server/services/preconfiguration.ts index 18726cdab4452..cf0ee7e70ca15 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -43,7 +43,6 @@ import { type InputsOverride, packagePolicyService } from './package_policy'; import { preconfigurePackageInputs } from './package_policy'; import { appContextService } from './app_context'; import type { UpgradeManagedPackagePoliciesResult } from './setup/managed_package_policies'; -import { isDefaultAgentlessPolicyEnabled } from './utils/agentless'; interface PreconfigurationResult { policies: Array<{ id: string; updated_at: string }>; @@ -163,18 +162,6 @@ export async function ensurePreconfiguredPackagesAndPolicies( ); } - if ( - !isDefaultAgentlessPolicyEnabled() && - preconfiguredAgentPolicy?.supports_agentless !== undefined - ) { - throw new FleetError( - i18n.translate('xpack.fleet.preconfiguration.support_agentless', { - defaultMessage: - '`supports_agentless` is only allowed in serverless environments that support the agentless feature', - }) - ); - } - const namespacedSoClient = preconfiguredAgentPolicy.space_id ? appContextService.getInternalUserSOClientForSpaceId(preconfiguredAgentPolicy.space_id) : appContextService.getInternalUserSOClientForSpaceId(DEFAULT_NAMESPACE_STRING); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index d2c35721fdddb..6d57eec4f3b99 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -20332,7 +20332,6 @@ "xpack.fleet.preconfiguration.packageMissingError": "Impossible d'ajouter [{agentPolicyName}]. [{pkgName}] n'est pas installé. Veuillez ajouter [{pkgName}] à [{packagesConfigValue}] ou le retirer de [{packagePolicyName}].", "xpack.fleet.preconfiguration.packageRejectedError": "Impossible d'ajouter [{agentPolicyName}]. [{pkgName}] n'a pas pu être installé en raison d’une erreur : [{errorMessage}].", "xpack.fleet.preconfiguration.policyDeleted": "La politique préconfigurée {id} a été supprimée ; ignorer la création", - "xpack.fleet.preconfiguration.support_agentless": "`supports_agentless` n'est autorisé que dans les environnements sans serveur prenant en charge la fonctionnalité sans agent", "xpack.fleet.renameAgentTags.errorNotificationTitle": "La balise n’a pas pu être renommée", "xpack.fleet.renameAgentTags.successNotificationTitle": "Balise renommée", "xpack.fleet.requestDiagnostics.calloutText": "Les fichiers de diagnostics sont stockés dans Elasticsearch, et ils peuvent donc engendrer des coûts de stockage. Par défaut, les fichiers sont périodiquement supprimés via une stratégie ILM.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index bc4f0b3f6cf1a..97e97f1e97c51 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -20082,7 +20082,6 @@ "xpack.fleet.preconfiguration.packageMissingError": "[{agentPolicyName}]を追加できませんでした。[{pkgName}]がインストールされていません。[{pkgName}]を[{packagesConfigValue}]に追加するか、[{packagePolicyName}]から削除してください。", "xpack.fleet.preconfiguration.packageRejectedError": "[{agentPolicyName}]を追加できませんでした。エラーのため、[{pkgName}]をインストールできませんでした:[{errorMessage}]", "xpack.fleet.preconfiguration.policyDeleted": "構成済みのポリシー{id}が削除されました。作成をスキップしています", - "xpack.fleet.preconfiguration.support_agentless": "supports_agentlessは、エージェントレス機能をサポートするサーバーレス環境でのみ許可されます", "xpack.fleet.renameAgentTags.errorNotificationTitle": "タグ名の変更が失敗しました", "xpack.fleet.renameAgentTags.successNotificationTitle": "タグ名が変更されました", "xpack.fleet.requestDiagnostics.calloutText": "診断ファイルはElasticsearchに保存されるため、ストレージコストが発生する可能性があります。デフォルトでは、ILMポリシーによって、ファイルが定期的に削除されます。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index e018909babf64..7194f977d4787 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -20112,7 +20112,6 @@ "xpack.fleet.preconfiguration.packageMissingError": "无法添加 [{agentPolicyName}]。[{pkgName}] 未安装,请将 [{pkgName}] 添加到 [{packagesConfigValue}] 或将其从 [{packagePolicyName}] 中移除。", "xpack.fleet.preconfiguration.packageRejectedError": "无法添加 [{agentPolicyName}]。无法安装 [{pkgName}],因为出现错误:[{errorMessage}]", "xpack.fleet.preconfiguration.policyDeleted": "预配置的策略 {id} 已删除;将跳过创建", - "xpack.fleet.preconfiguration.support_agentless": "只有支持无代理功能的无服务器环境才允许使用 `supports_agentless`", "xpack.fleet.renameAgentTags.errorNotificationTitle": "标签重命名失败", "xpack.fleet.renameAgentTags.successNotificationTitle": "标签已重命名", "xpack.fleet.requestDiagnostics.calloutText": "诊断文件存储在 Elasticsearch 中,因此可能产生存储成本。默认情况下,会通过 ILM 策略定期删除文件。", From 9f291dc55ec4c82380b81aa2fb9d7a8d84a1ff22 Mon Sep 17 00:00:00 2001 From: Kevin Lacabane Date: Wed, 16 Oct 2024 21:03:48 +0200 Subject: [PATCH 29/30] [eem] use current user to delete indices (#195886) We were trying to cleanup `.entities` indices with the system user that does not have necessary privileges. This failed silently because of `ignore_unavailable: true` --- .../server/lib/entities/delete_index.ts | 13 ++--- .../entities/uninstall_entity_definition.ts | 27 +++------- .../server/lib/entity_client.ts | 50 +++++++++++++------ .../plugins/entity_manager/server/plugin.ts | 4 +- .../server/routes/enablement/disable.ts | 8 ++- .../entity_store_data_client.test.ts | 5 +- .../entity_store/entity_store_data_client.ts | 38 +++++++------- .../server/request_context_factory.ts | 4 +- .../apis/entity_manager/definitions.ts | 8 ++- 9 files changed, 82 insertions(+), 75 deletions(-) diff --git a/x-pack/plugins/entity_manager/server/lib/entities/delete_index.ts b/x-pack/plugins/entity_manager/server/lib/entities/delete_index.ts index 433b6e392c27e..d40d9975a8820 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/delete_index.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/delete_index.ts @@ -7,7 +7,7 @@ import { ElasticsearchClient, Logger } from '@kbn/core/server'; import { EntityDefinition } from '@kbn/entities-schema'; -import { generateHistoryIndexName, generateLatestIndexName } from './helpers/generate_component_id'; +import { generateLatestIndexName } from './helpers/generate_component_id'; export async function deleteIndices( esClient: ElasticsearchClient, @@ -15,15 +15,8 @@ export async function deleteIndices( logger: Logger ) { try { - const { indices: historyIndices } = await esClient.indices.resolveIndex({ - name: `${generateHistoryIndexName(definition)}.*`, - expand_wildcards: 'all', - }); - const indices = [ - ...historyIndices.map(({ name }) => name), - generateLatestIndexName(definition), - ]; - await esClient.indices.delete({ index: indices, ignore_unavailable: true }); + const index = generateLatestIndexName(definition); + await esClient.indices.delete({ index, ignore_unavailable: true }); } catch (e) { logger.error(`Unable to remove entity definition index [${definition.id}}]`); throw e; diff --git a/x-pack/plugins/entity_manager/server/lib/entities/uninstall_entity_definition.ts b/x-pack/plugins/entity_manager/server/lib/entities/uninstall_entity_definition.ts index d0e0410b6e422..f8e27353082d0 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/uninstall_entity_definition.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/uninstall_entity_definition.ts @@ -10,63 +10,48 @@ import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { EntityDefinition } from '@kbn/entities-schema'; import { Logger } from '@kbn/logging'; import { deleteEntityDefinition } from './delete_entity_definition'; -import { deleteIndices } from './delete_index'; import { deleteIngestPipelines } from './delete_ingest_pipeline'; -import { findEntityDefinitions } from './find_entity_definition'; import { deleteTemplates } from '../manage_index_templates'; import { stopTransforms } from './stop_transforms'; import { deleteTransforms } from './delete_transforms'; +import { EntityClient } from '../entity_client'; export async function uninstallEntityDefinition({ definition, esClient, soClient, logger, - deleteData = false, }: { definition: EntityDefinition; esClient: ElasticsearchClient; soClient: SavedObjectsClientContract; logger: Logger; - deleteData?: boolean; }) { await stopTransforms(esClient, definition, logger); await deleteTransforms(esClient, definition, logger); await deleteIngestPipelines(esClient, definition, logger); - if (deleteData) { - await deleteIndices(esClient, definition, logger); - } - await deleteTemplates(esClient, definition, logger); await deleteEntityDefinition(soClient, definition); } export async function uninstallBuiltInEntityDefinitions({ - esClient, - soClient, - logger, + entityClient, deleteData = false, }: { - esClient: ElasticsearchClient; - soClient: SavedObjectsClientContract; - logger: Logger; + entityClient: EntityClient; deleteData?: boolean; }): Promise { - const definitions = await findEntityDefinitions({ - soClient, - esClient, - builtIn: true, - }); + const { definitions } = await entityClient.getEntityDefinitions({ builtIn: true }); await Promise.all( - definitions.map(async (definition) => { - await uninstallEntityDefinition({ definition, esClient, soClient, logger, deleteData }); + definitions.map(async ({ id }) => { + await entityClient.deleteEntityDefinition({ id, deleteData }); }) ); diff --git a/x-pack/plugins/entity_manager/server/lib/entity_client.ts b/x-pack/plugins/entity_manager/server/lib/entity_client.ts index 1bb1322be356f..dcb3dfab8f328 100644 --- a/x-pack/plugins/entity_manager/server/lib/entity_client.ts +++ b/x-pack/plugins/entity_manager/server/lib/entity_client.ts @@ -7,7 +7,7 @@ import { EntityDefinition, EntityDefinitionUpdate } from '@kbn/entities-schema'; import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; -import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; import { Logger } from '@kbn/logging'; import { installEntityDefinition, @@ -20,13 +20,14 @@ import { uninstallEntityDefinition } from './entities/uninstall_entity_definitio import { EntityDefinitionNotFound } from './entities/errors/entity_not_found'; import { stopTransforms } from './entities/stop_transforms'; +import { deleteIndices } from './entities/delete_index'; import { EntityDefinitionWithState } from './entities/types'; import { EntityDefinitionUpdateConflict } from './entities/errors/entity_definition_update_conflict'; export class EntityClient { constructor( private options: { - esClient: ElasticsearchClient; + clusterClient: IScopedClusterClient; soClient: SavedObjectsClientContract; logger: Logger; } @@ -39,15 +40,16 @@ export class EntityClient { definition: EntityDefinition; installOnly?: boolean; }) { + const secondaryAuthClient = this.options.clusterClient.asSecondaryAuthUser; const installedDefinition = await installEntityDefinition({ definition, + esClient: secondaryAuthClient, soClient: this.options.soClient, - esClient: this.options.esClient, logger: this.options.logger, }); if (!installOnly) { - await startTransforms(this.options.esClient, installedDefinition, this.options.logger); + await startTransforms(secondaryAuthClient, installedDefinition, this.options.logger); } return installedDefinition; @@ -60,10 +62,11 @@ export class EntityClient { id: string; definitionUpdate: EntityDefinitionUpdate; }) { + const secondaryAuthClient = this.options.clusterClient.asSecondaryAuthUser; const definition = await findEntityDefinitionById({ id, soClient: this.options.soClient, - esClient: this.options.esClient, + esClient: secondaryAuthClient, includeState: true, }); @@ -87,22 +90,22 @@ export class EntityClient { definition, definitionUpdate, soClient: this.options.soClient, - esClient: this.options.esClient, + esClient: secondaryAuthClient, logger: this.options.logger, }); if (shouldRestartTransforms) { - await startTransforms(this.options.esClient, updatedDefinition, this.options.logger); + await startTransforms(secondaryAuthClient, updatedDefinition, this.options.logger); } return updatedDefinition; } async deleteEntityDefinition({ id, deleteData = false }: { id: string; deleteData?: boolean }) { - const [definition] = await findEntityDefinitions({ + const secondaryAuthClient = this.options.clusterClient.asSecondaryAuthUser; + const definition = await findEntityDefinitionById({ id, - perPage: 1, + esClient: secondaryAuthClient, soClient: this.options.soClient, - esClient: this.options.esClient, }); if (!definition) { @@ -113,11 +116,20 @@ export class EntityClient { await uninstallEntityDefinition({ definition, - deleteData, + esClient: secondaryAuthClient, soClient: this.options.soClient, - esClient: this.options.esClient, logger: this.options.logger, }); + + if (deleteData) { + // delete data with current user as system user does not have + // .entities privileges + await deleteIndices( + this.options.clusterClient.asCurrentUser, + definition, + this.options.logger + ); + } } async getEntityDefinitions({ @@ -136,7 +148,7 @@ export class EntityClient { builtIn?: boolean; }) { const definitions = await findEntityDefinitions({ - esClient: this.options.esClient, + esClient: this.options.clusterClient.asSecondaryAuthUser, soClient: this.options.soClient, page, perPage, @@ -150,10 +162,18 @@ export class EntityClient { } async startEntityDefinition(definition: EntityDefinition) { - return startTransforms(this.options.esClient, definition, this.options.logger); + return startTransforms( + this.options.clusterClient.asSecondaryAuthUser, + definition, + this.options.logger + ); } async stopEntityDefinition(definition: EntityDefinition) { - return stopTransforms(this.options.esClient, definition, this.options.logger); + return stopTransforms( + this.options.clusterClient.asSecondaryAuthUser, + definition, + this.options.logger + ); } } diff --git a/x-pack/plugins/entity_manager/server/plugin.ts b/x-pack/plugins/entity_manager/server/plugin.ts index 2677b78042620..152b1b59b3107 100644 --- a/x-pack/plugins/entity_manager/server/plugin.ts +++ b/x-pack/plugins/entity_manager/server/plugin.ts @@ -99,9 +99,9 @@ export class EntityManagerServerPlugin request: KibanaRequest; coreStart: CoreStart; }) { - const esClient = coreStart.elasticsearch.client.asScoped(request).asSecondaryAuthUser; + const clusterClient = coreStart.elasticsearch.client.asScoped(request); const soClient = coreStart.savedObjects.getScopedClient(request); - return new EntityClient({ esClient, soClient, logger: this.logger }); + return new EntityClient({ clusterClient, soClient, logger: this.logger }); } public start( diff --git a/x-pack/plugins/entity_manager/server/routes/enablement/disable.ts b/x-pack/plugins/entity_manager/server/routes/enablement/disable.ts index 9c1c4f403636b..f8629fe46497b 100644 --- a/x-pack/plugins/entity_manager/server/routes/enablement/disable.ts +++ b/x-pack/plugins/entity_manager/server/routes/enablement/disable.ts @@ -49,7 +49,7 @@ export const disableEntityDiscoveryRoute = createEntityManagerServerRoute({ deleteData: z.optional(BooleanFromString).default(false), }), }), - handler: async ({ context, response, params, logger, server }) => { + handler: async ({ context, request, response, params, logger, server, getScopedClient }) => { try { const esClientAsCurrentUser = (await context.core).elasticsearch.client.asCurrentUser; const canDisable = await canDisableEntityDiscovery(esClientAsCurrentUser); @@ -62,15 +62,13 @@ export const disableEntityDiscoveryRoute = createEntityManagerServerRoute({ }); } - const esClient = (await context.core).elasticsearch.client.asSecondaryAuthUser; + const entityClient = await getScopedClient({ request }); const soClient = (await context.core).savedObjects.getClient({ includedHiddenTypes: [EntityDiscoveryApiKeyType.name], }); await uninstallBuiltInEntityDefinitions({ - soClient, - esClient, - logger, + entityClient, deleteData: params.query.deleteData, }); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts index 4156ea1dbd4ea..8079e54ac9ba6 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts @@ -18,10 +18,11 @@ import type { AppClient } from '../../..'; describe('EntityStoreDataClient', () => { const mockSavedObjectClient = savedObjectsClientMock.create(); - const esClientMock = elasticsearchServiceMock.createScopedClusterClient().asInternalUser; + const clusterClientMock = elasticsearchServiceMock.createScopedClusterClient(); + const esClientMock = clusterClientMock.asCurrentUser; const loggerMock = loggingSystemMock.createLogger(); const dataClient = new EntityStoreDataClient({ - esClient: esClientMock, + clusterClient: clusterClientMock, logger: loggerMock, namespace: 'default', soClient: mockSavedObjectClient, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts index d2e21a1d10903..5b1acaa433cd0 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts @@ -10,6 +10,7 @@ import type { ElasticsearchClient, SavedObjectsClientContract, AuditLogger, + IScopedClusterClient, } from '@kbn/core/server'; import { EntityClient } from '@kbn/entityManager-plugin/server/lib/entity_client'; import type { SortOrder } from '@elastic/elasticsearch/lib/api/types'; @@ -55,7 +56,7 @@ import { interface EntityStoreClientOpts { logger: Logger; - esClient: ElasticsearchClient; + clusterClient: IScopedClusterClient; namespace: string; soClient: SavedObjectsClientContract; taskManager?: TaskManagerStartContract; @@ -79,12 +80,14 @@ export class EntityStoreDataClient { private assetCriticalityMigrationClient: AssetCriticalityEcsMigrationClient; private entityClient: EntityClient; private riskScoreDataClient: RiskScoreDataClient; + private esClient: ElasticsearchClient; constructor(private readonly options: EntityStoreClientOpts) { - const { esClient, logger, soClient, auditLogger, kibanaVersion, namespace } = options; + const { clusterClient, logger, soClient, auditLogger, kibanaVersion, namespace } = options; + this.esClient = clusterClient.asCurrentUser; this.entityClient = new EntityClient({ - esClient, + clusterClient, soClient, logger, }); @@ -95,14 +98,14 @@ export class EntityStoreDataClient { }); this.assetCriticalityMigrationClient = new AssetCriticalityEcsMigrationClient({ - esClient, + esClient: this.esClient, logger, auditLogger, }); this.riskScoreDataClient = new RiskScoreDataClient({ soClient, - esClient, + esClient: this.esClient, logger, namespace, kibanaVersion, @@ -165,7 +168,7 @@ export class EntityStoreDataClient { filter: string, pipelineDebugMode: boolean ) { - const { esClient, logger, namespace, appClient, dataViewsService } = this.options; + const { logger, namespace, appClient, dataViewsService } = this.options; const indexPatterns = await buildIndexPatterns(namespace, appClient, dataViewsService); const unitedDefinition = getUnitedEntityDefinition({ @@ -200,12 +203,12 @@ export class EntityStoreDataClient { // this is because the enrich policy will fail if the index does not exist with the correct fields await createEntityIndexComponentTemplate({ unitedDefinition, - esClient, + esClient: this.esClient, }); debugLog(`Created entity index component template`); await createEntityIndex({ entityType, - esClient, + esClient: this.esClient, namespace, logger, }); @@ -215,12 +218,12 @@ export class EntityStoreDataClient { // this is because the pipeline will fail if the enrich index does not exist await createFieldRetentionEnrichPolicy({ unitedDefinition, - esClient, + esClient: this.esClient, }); debugLog(`Created field retention enrich policy`); await executeFieldRetentionEnrichPolicy({ unitedDefinition, - esClient, + esClient: this.esClient, logger, }); debugLog(`Executed field retention enrich policy`); @@ -228,7 +231,7 @@ export class EntityStoreDataClient { debugMode: pipelineDebugMode, unitedDefinition, logger, - esClient, + esClient: this.esClient, }); debugLog(`Created @platform pipeline`); @@ -325,8 +328,9 @@ export class EntityStoreDataClient { taskManager: TaskManagerStartContract, options = { deleteData: false, deleteEngine: true } ) { - const { namespace, logger, esClient, appClient, dataViewsService } = this.options; + const { namespace, logger, appClient, dataViewsService } = this.options; const { deleteData, deleteEngine } = options; + const descriptor = await this.engineClient.maybeGet(entityType); const indexPatterns = await buildIndexPatterns(namespace, appClient, dataViewsService); const unitedDefinition = getUnitedEntityDefinition({ @@ -348,22 +352,22 @@ export class EntityStoreDataClient { } await deleteEntityIndexComponentTemplate({ unitedDefinition, - esClient, + esClient: this.esClient, }); await deletePlatformPipeline({ unitedDefinition, logger, - esClient, + esClient: this.esClient, }); await deleteFieldRetentionEnrichPolicy({ unitedDefinition, - esClient, + esClient: this.esClient, }); if (deleteData) { await deleteEntityIndex({ entityType, - esClient, + esClient: this.esClient, namespace, logger, }); @@ -402,7 +406,7 @@ export class EntityStoreDataClient { const sort = sortField ? [{ [sortField]: sortOrder }] : undefined; const query = filterQuery ? JSON.parse(filterQuery) : undefined; - const response = await this.options.esClient.search({ + const response = await this.esClient.search({ index, query, size: Math.min(perPage, MAX_SEARCH_RESPONSE_SIZE), diff --git a/x-pack/plugins/security_solution/server/request_context_factory.ts b/x-pack/plugins/security_solution/server/request_context_factory.ts index 0782fa25c71eb..d2bd579dc6b03 100644 --- a/x-pack/plugins/security_solution/server/request_context_factory.ts +++ b/x-pack/plugins/security_solution/server/request_context_factory.ts @@ -199,14 +199,14 @@ export class RequestContextFactory implements IRequestContextFactory { }) ), getEntityStoreDataClient: memoize(() => { - const esClient = coreContext.elasticsearch.client.asCurrentUser; + const clusterClient = coreContext.elasticsearch.client; const logger = options.logger; const soClient = coreContext.savedObjects.client; return new EntityStoreDataClient({ namespace: getSpaceId(), + clusterClient, dataViewsService, appClient: getAppClient(), - esClient, logger, soClient, taskManager: startPlugins.taskManager, diff --git a/x-pack/test/api_integration/apis/entity_manager/definitions.ts b/x-pack/test/api_integration/apis/entity_manager/definitions.ts index b51a26ad7b5ad..a1fdab08ff42a 100644 --- a/x-pack/test/api_integration/apis/entity_manager/definitions.ts +++ b/x-pack/test/api_integration/apis/entity_manager/definitions.ts @@ -154,7 +154,6 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await esDeleteAllIndices(dataForgeIndices); - await uninstallDefinition(supertest, { id: mockDefinition.id, deleteData: true }); await cleanup({ client: esClient, config: dataForgeConfig, logger }); }); @@ -171,6 +170,13 @@ export default function ({ getService }: FtrProviderContext) { const parsedSample = entityLatestSchema.safeParse(sample.hits.hits[0]._source); expect(parsedSample.success).to.be(true); }); + + it('should delete entities data when specified', async () => { + const index = generateLatestIndexName(mockDefinition); + expect(await esClient.indices.exists({ index })).to.be(true); + await uninstallDefinition(supertest, { id: mockDefinition.id, deleteData: true }); + expect(await esClient.indices.exists({ index })).to.be(false); + }); }); }); } From 35bc785feb358be8d8ef586f81880c9910cefc0b Mon Sep 17 00:00:00 2001 From: "Quynh Nguyen (Quinn)" <43350163+qn895@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:08:16 -0500 Subject: [PATCH 30/30] [ES|QL] Fix duplicate autocomplete suggestions for where clause, and suggestions with no space in between (#195771) ## Summary Fix duplicate autocomplete suggestions for where clause, and https://github.com/elastic/kibana/issues/192596 and https://github.com/elastic/kibana/issues/192598 with `WHERE` suggestions are inserted too far back https://github.com/user-attachments/assets/e28357cd-84b8-4f57-a261-ab25121cd102 ### Checklist Delete any items that are not applicable to this PR. - [ ] 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) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [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 - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] 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) ### Risk Matrix Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) Co-authored-by: Elastic Machine --- .../src/autocomplete/autocomplete.test.ts | 30 +++++++------------ .../src/autocomplete/autocomplete.ts | 18 ++++++++--- .../src/autocomplete/complete_items.ts | 3 +- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts index 8524cd4950955..e463902554074 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts @@ -1262,41 +1262,33 @@ describe('autocomplete', () => { describe('Replacement ranges are attached when needed', () => { testSuggestions('FROM a | WHERE doubleField IS NOT N/', [ { text: 'IS NOT NULL', rangeToReplace: { start: 28, end: 35 } }, - { text: 'IS NULL', rangeToReplace: { start: 35, end: 35 } }, + { text: 'IS NULL', rangeToReplace: { start: 36, end: 36 } }, '!= $0', - '< $0', - '<= $0', '== $0', - '> $0', - '>= $0', 'IN $0', + 'AND $0', + 'NOT', + 'OR $0', ]); testSuggestions('FROM a | WHERE doubleField IS N/', [ { text: 'IS NOT NULL', rangeToReplace: { start: 28, end: 31 } }, { text: 'IS NULL', rangeToReplace: { start: 28, end: 31 } }, - { text: '!= $0', rangeToReplace: { start: 31, end: 31 } }, - '< $0', - '<= $0', + { text: '!= $0', rangeToReplace: { start: 32, end: 32 } }, '== $0', - '> $0', - '>= $0', 'IN $0', + 'AND $0', + 'NOT', + 'OR $0', ]); testSuggestions('FROM a | EVAL doubleField IS NOT N/', [ { text: 'IS NOT NULL', rangeToReplace: { start: 27, end: 34 } }, 'IS NULL', - '% $0', - '* $0', - '+ $0', - '- $0', - '/ $0', '!= $0', - '< $0', - '<= $0', '== $0', - '> $0', - '>= $0', 'IN $0', + 'AND $0', + 'NOT', + 'OR $0', ]); describe('dot-separated field names', () => { testSuggestions( diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts index 5d885379f1a94..cf41fd2506c72 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts @@ -324,10 +324,16 @@ function findNewVariable(variables: Map) { function workoutBuiltinOptions( nodeArg: ESQLAstItem, references: Pick -): { skipAssign: boolean } { +): { skipAssign: boolean; commandsToInclude?: string[] } { + const commandsToInclude = + (isSingleItem(nodeArg) && nodeArg.text?.toLowerCase().trim().endsWith('null')) ?? false + ? ['and', 'or'] + : undefined; + // skip assign operator if it's a function or an existing field to avoid promoting shadowing return { skipAssign: Boolean(!isColumnItem(nodeArg) || getColumnForASTNode(nodeArg, references)), + commandsToInclude, }; } @@ -447,7 +453,10 @@ function isFunctionArgComplete( } const hasCorrectTypes = fnDefinition.signatures.some((def) => { return arg.args.every((a, index) => { - return def.params[index].type === extractTypeFromASTArg(a, references); + return ( + (fnDefinition.name.endsWith('null') && def.params[index].type === 'any') || + def.params[index].type === extractTypeFromASTArg(a, references) + ); }); }); if (!hasCorrectTypes) { @@ -1140,11 +1149,12 @@ async function getBuiltinFunctionNextArgument( } return suggestions.map((s) => { const overlap = getOverlapRange(queryText, s.text); + const offset = overlap.start === overlap.end ? 1 : 0; return { ...s, rangeToReplace: { - start: overlap.start, - end: overlap.end, + start: overlap.start + offset, + end: overlap.end + offset, }, }; }); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts index 42bb02058023b..8d598eb5f2f11 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts @@ -59,10 +59,11 @@ export const getBuiltinCompatibleFunctionDefinition = ( option: string | undefined, argType: FunctionParameterType, returnTypes?: FunctionReturnType[], - { skipAssign }: { skipAssign?: boolean } = {} + { skipAssign, commandsToInclude }: { skipAssign?: boolean; commandsToInclude?: string[] } = {} ): SuggestionRawDefinition[] => { const compatibleFunctions = [...builtinFunctions, ...getTestFunctions()].filter( ({ name, supportedCommands, supportedOptions, signatures, ignoreAsSuggestion }) => + (command === 'where' && commandsToInclude ? commandsToInclude.indexOf(name) > -1 : true) && !ignoreAsSuggestion && !/not_/.test(name) && (!skipAssign || name !== '=') &&