From 4cb3a740d5c9b8eb3d4d48437bfa7c9911debf68 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 16 Aug 2023 13:08:42 +0100 Subject: [PATCH 01/11] skip flaky suite (#164050) --- .../plugins/cases/public/components/description/index.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/description/index.test.tsx b/x-pack/plugins/cases/public/components/description/index.test.tsx index f519c7af3eb19..1c64d92bf3320 100644 --- a/x-pack/plugins/cases/public/components/description/index.test.tsx +++ b/x-pack/plugins/cases/public/components/description/index.test.tsx @@ -198,7 +198,8 @@ describe('Description', () => { expect(screen.queryByTestId('description-edit-icon')).not.toBeInTheDocument(); }); - describe('draft message', () => { + // FLAKY: https://github.com/elastic/kibana/issues/164050 + describe.skip('draft message', () => { const draftStorageKey = `cases.testAppId.basic-case-id.description.markdownEditor`; beforeEach(() => { From e4904929ab6ef9ae46de6039b67b7cb80acfa9f7 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 16 Aug 2023 13:10:25 +0100 Subject: [PATCH 02/11] skip flaky suite (#164049) --- .../plugins/cases/public/components/description/index.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/description/index.test.tsx b/x-pack/plugins/cases/public/components/description/index.test.tsx index 1c64d92bf3320..1b471fa7f045d 100644 --- a/x-pack/plugins/cases/public/components/description/index.test.tsx +++ b/x-pack/plugins/cases/public/components/description/index.test.tsx @@ -27,7 +27,8 @@ const defaultProps = { isLoadingDescription: false, }; -describe('Description', () => { +// FLAKY: https://github.com/elastic/kibana/issues/164049 +describe.skip('Description', () => { const onUpdateField = jest.fn(); let appMockRender: AppMockRenderer; From aef47f140c78128472e3e24b346a7c5499b2ec0e Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 16 Aug 2023 13:11:37 +0100 Subject: [PATCH 03/11] skip flaky suite (#164048) --- .../plugins/cases/public/components/description/index.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/cases/public/components/description/index.test.tsx b/x-pack/plugins/cases/public/components/description/index.test.tsx index 1b471fa7f045d..2f2a7bedf6dc3 100644 --- a/x-pack/plugins/cases/public/components/description/index.test.tsx +++ b/x-pack/plugins/cases/public/components/description/index.test.tsx @@ -28,6 +28,7 @@ const defaultProps = { }; // FLAKY: https://github.com/elastic/kibana/issues/164049 +// FLAKY: https://github.com/elastic/kibana/issues/164048 describe.skip('Description', () => { const onUpdateField = jest.fn(); let appMockRender: AppMockRenderer; From 2f07bf1042b8eeb99eedd9a47c89eaa6e784c198 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 16 Aug 2023 13:12:49 +0100 Subject: [PATCH 04/11] skip flaky suite (#164047) --- .../plugins/cases/public/components/description/index.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/cases/public/components/description/index.test.tsx b/x-pack/plugins/cases/public/components/description/index.test.tsx index 2f2a7bedf6dc3..20865890146cd 100644 --- a/x-pack/plugins/cases/public/components/description/index.test.tsx +++ b/x-pack/plugins/cases/public/components/description/index.test.tsx @@ -29,6 +29,7 @@ const defaultProps = { // FLAKY: https://github.com/elastic/kibana/issues/164049 // FLAKY: https://github.com/elastic/kibana/issues/164048 +// FLAKY: https://github.com/elastic/kibana/issues/164047 describe.skip('Description', () => { const onUpdateField = jest.fn(); let appMockRender: AppMockRenderer; From d1240d332502605657bf4a2b01f92f599557deab Mon Sep 17 00:00:00 2001 From: Carlos Crespo Date: Wed, 16 Aug 2023 14:13:22 +0200 Subject: [PATCH 05/11] [Infra UI] Unskip alerts flyout test (#163919) closes [#157712](https://github.com/elastic/kibana/issues/157712) closes [#157767](https://github.com/elastic/kibana/issues/157767) closes [#157711](https://github.com/elastic/kibana/issues/157711) ## Summary Unskips "alerts flyouts" test. What cause the test to fail was possibly solved by https://github.com/elastic/kibana/pull/162896 ### How to test ``` yarn test:ftr:server --config x-pack/test/functional/apps/infra/config.ts ``` ``` node scripts/functional_test_runner --config=x-pack/test/functional/apps/infra/config.ts --include x-pack/test/functional/apps/infra/home_page.ts ``` https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2888 --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../test/functional/apps/infra/home_page.ts | 5 ++-- .../page_objects/infra_home_page.ts | 28 ++++++++++++++++--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts index 79fa4d0eea06e..7fedb18db416c 100644 --- a/x-pack/test/functional/apps/infra/home_page.ts +++ b/x-pack/test/functional/apps/infra/home_page.ts @@ -199,8 +199,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/157711 - describe.skip('alerts flyouts', () => { + describe('alerts flyouts', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); await pageObjects.common.navigateToApp('infraOps'); @@ -217,7 +216,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.infraHome.closeAlertFlyout(); }); - it('should open and close inventory alert flyout', async () => { + it('should open and close metrics threshold alert flyout', async () => { await pageObjects.infraHome.openMetricsThresholdAlertFlyout(); await pageObjects.infraHome.closeAlertFlyout(); }); diff --git a/x-pack/test/functional/page_objects/infra_home_page.ts b/x-pack/test/functional/page_objects/infra_home_page.ts index f9f088b106375..aed3558cfdcb4 100644 --- a/x-pack/test/functional/page_objects/infra_home_page.ts +++ b/x-pack/test/functional/page_objects/infra_home_page.ts @@ -335,20 +335,40 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide await testSubjects.missingOrFail('metrics-alert-menu'); }, + async dismissDatePickerTooltip() { + const isTooltipOpen = await testSubjects.exists(`waffleDatePickerIntervalTooltip`, { + timeout: 1000, + }); + + if (isTooltipOpen) { + await testSubjects.click(`waffleDatePickerIntervalTooltip`); + } + }, + async openInventoryAlertFlyout() { + await this.dismissDatePickerTooltip(); await testSubjects.click('infrastructure-alerts-and-rules'); await testSubjects.click('inventory-alerts-menu-option'); - await testSubjects.click('inventory-alerts-create-rule'); + + // forces date picker tooltip to close in case it pops up after Alerts and rules opens + await testSubjects.moveMouseTo('contextMenuPanelTitleButton'); + + await retry.tryForTime(1000, () => testSubjects.click('inventory-alerts-create-rule')); await testSubjects.missingOrFail('inventory-alerts-create-rule', { timeout: 30000 }); - await testSubjects.find('euiFlyoutCloseButton'); }, async openMetricsThresholdAlertFlyout() { + await this.dismissDatePickerTooltip(); await testSubjects.click('infrastructure-alerts-and-rules'); await testSubjects.click('metrics-threshold-alerts-menu-option'); - await testSubjects.click('metrics-threshold-alerts-create-rule'); + + // forces date picker tooltip to close in case it pops up after Alerts and rules opens + await testSubjects.moveMouseTo('contextMenuPanelTitleButton'); + + await retry.tryForTime(1000, () => + testSubjects.click('metrics-threshold-alerts-create-rule') + ); await testSubjects.missingOrFail('metrics-threshold-alerts-create-rule', { timeout: 30000 }); - await testSubjects.find('euiFlyoutCloseButton'); }, async closeAlertFlyout() { From 85de4abc95b13b206a5d57467b94817417053f17 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 16 Aug 2023 13:14:41 +0100 Subject: [PATCH 06/11] skip flaky suite (#164046) --- .../plugins/cases/public/components/description/index.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/cases/public/components/description/index.test.tsx b/x-pack/plugins/cases/public/components/description/index.test.tsx index 20865890146cd..667730856c60e 100644 --- a/x-pack/plugins/cases/public/components/description/index.test.tsx +++ b/x-pack/plugins/cases/public/components/description/index.test.tsx @@ -30,6 +30,7 @@ const defaultProps = { // FLAKY: https://github.com/elastic/kibana/issues/164049 // FLAKY: https://github.com/elastic/kibana/issues/164048 // FLAKY: https://github.com/elastic/kibana/issues/164047 +// FLAKY: https://github.com/elastic/kibana/issues/164046 describe.skip('Description', () => { const onUpdateField = jest.fn(); let appMockRender: AppMockRenderer; From 2244718a9257eb1eb7d4480028675fe732063ad6 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 16 Aug 2023 13:15:40 +0100 Subject: [PATCH 07/11] skip flaky suite (#164045) --- .../plugins/cases/public/components/description/index.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/cases/public/components/description/index.test.tsx b/x-pack/plugins/cases/public/components/description/index.test.tsx index 667730856c60e..62810de85cbe1 100644 --- a/x-pack/plugins/cases/public/components/description/index.test.tsx +++ b/x-pack/plugins/cases/public/components/description/index.test.tsx @@ -31,6 +31,7 @@ const defaultProps = { // FLAKY: https://github.com/elastic/kibana/issues/164048 // FLAKY: https://github.com/elastic/kibana/issues/164047 // FLAKY: https://github.com/elastic/kibana/issues/164046 +// FLAKY: https://github.com/elastic/kibana/issues/164045 describe.skip('Description', () => { const onUpdateField = jest.fn(); let appMockRender: AppMockRenderer; From 9604db3a33d20a09ec6d45b1921e41d5a5d18135 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 16 Aug 2023 13:16:44 +0100 Subject: [PATCH 08/11] skip flaky suite (#164044) --- .../plugins/cases/public/components/description/index.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/cases/public/components/description/index.test.tsx b/x-pack/plugins/cases/public/components/description/index.test.tsx index 62810de85cbe1..e077c0896d67d 100644 --- a/x-pack/plugins/cases/public/components/description/index.test.tsx +++ b/x-pack/plugins/cases/public/components/description/index.test.tsx @@ -32,6 +32,7 @@ const defaultProps = { // FLAKY: https://github.com/elastic/kibana/issues/164047 // FLAKY: https://github.com/elastic/kibana/issues/164046 // FLAKY: https://github.com/elastic/kibana/issues/164045 +// FLAKY: https://github.com/elastic/kibana/issues/164044 describe.skip('Description', () => { const onUpdateField = jest.fn(); let appMockRender: AppMockRenderer; From e78d61789fe1f9f48f8c13436a34dd341b490894 Mon Sep 17 00:00:00 2001 From: Gloria Hornero Date: Wed, 16 Aug 2023 14:38:11 +0200 Subject: [PATCH 09/11] [Security Solution] Updates codeowners file (#164026) --- .github/CODEOWNERS | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 89e4a2c008727..684f2ffd3b548 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1283,7 +1283,11 @@ x-pack/plugins/security_solution/server/lib/telemetry/ @elastic/security-data-an ## Security Solution sub teams - security-engineering-productivity x-pack/test/security_solution_cypress/cypress/README.md @elastic/security-engineering-productivity -x-pack/test/security_solution_cypress @elastic/security-engineering-productivity +x-pack/test/security_solution_cypress/es_archives @elastic/security-engineering-productivity +x-pack/test/security_solution_cypress/cli_config.ts @elastic/security-engineering-productivity +x-pack/test/security_solution_cypress/config.ts @elastic/security-engineering-productivity +x-pack/test/security_solution_cypress/runner.ts @elastic/security-engineering-productivity +x-pack/test/security_solution_cypress/serverless_config.ts @elastic/security-engineering-productivity ## Security Solution sub teams - adaptive-workload-protection x-pack/plugins/security_solution/public/common/components/sessions_viewer @elastic/sec-cloudnative-integrations From 736b16dfcd5ef3ea04fb89ddb45dd19defd302c2 Mon Sep 17 00:00:00 2001 From: Philippe Oberti Date: Wed, 16 Aug 2023 14:39:34 +0200 Subject: [PATCH 10/11] [Security Solution] expandable flyout - show full alert reason in preview panel (#163667) --- .../correlations_details_alerts_table.tsx | 5 +- .../components/alert_reason_preview.test.tsx | 47 +++++++ .../components/alert_reason_preview.tsx | 50 ++++++++ .../flyout/preview/components/test_ids.ts | 2 + .../flyout/preview/components/translations.ts | 5 + .../public/flyout/preview/context.tsx | 24 +++- .../public/flyout/preview/index.tsx | 3 +- .../mocks/mock_preview_panel_context.ts | 3 + .../public/flyout/preview/panels.tsx | 8 +- .../public/flyout/preview/translations.ts | 5 + .../right/components/description.stories.tsx | 92 -------------- .../right/components/description.test.tsx | 115 +++++++++++------- .../right/components/reason.stories.tsx | 45 ------- .../flyout/right/components/reason.test.tsx | 103 +++++++++------- .../public/flyout/right/components/reason.tsx | 90 ++++++++++---- .../flyout/right/components/test_ids.ts | 2 + .../flyout/right/components/translations.ts | 12 ++ .../flyout/right/hooks/use_process_data.ts | 7 +- .../public/flyout/right/mocks/mock_context.ts | 4 +- ...s_preview_panel_alert_reason_preview.cy.ts | 42 +++++++ ...ert_details_right_panel_overview_tab.cy.ts | 3 +- ...ails_preview_panel_alert_reason_preview.ts | 13 ++ .../alert_details_right_panel_overview_tab.ts | 3 + .../alert_details_right_panel_overview_tab.ts | 16 +++ 24 files changed, 437 insertions(+), 262 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.test.tsx create mode 100644 x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.tsx delete mode 100644 x-pack/plugins/security_solution/public/flyout/right/components/description.stories.tsx delete mode 100644 x-pack/plugins/security_solution/public/flyout/right/components/reason.stories.tsx create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_alert_reason_preview.cy.ts create mode 100644 x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel_alert_reason_preview.ts diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details_alerts_table.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details_alerts_table.tsx index 79ce5e8f4bf0d..28d05d3a08d70 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details_alerts_table.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details_alerts_table.tsx @@ -10,6 +10,7 @@ import { type Criteria, EuiBasicTable, formatDate, EuiEmptyPrompt } from '@elast import { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; import { isRight } from 'fp-ts/lib/Either'; +import { ALERT_REASON, ALERT_RULE_NAME } from '@kbn/rule-data-utils'; import { SeverityBadge } from '../../../detections/components/rules/severity_badge'; import { usePaginatedAlerts } from '../hooks/use_paginated_alerts'; import { ERROR_MESSAGE, ERROR_TITLE } from '../../shared/translations'; @@ -26,12 +27,12 @@ export const columns = [ render: (value: string) => formatDate(value, TIMESTAMP_DATE_FORMAT), }, { - field: 'kibana.alert.rule.name', + field: ALERT_RULE_NAME, name: i18n.CORRELATIONS_RULE_COLUMN_TITLE, truncateText: true, }, { - field: 'kibana.alert.reason', + field: ALERT_REASON, name: i18n.CORRELATIONS_REASON_COLUMN_TITLE, truncateText: true, }, diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.test.tsx b/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.test.tsx new file mode 100644 index 0000000000000..30076fd3ca1d2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.test.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { PreviewPanelContext } from '../context'; +import { mockContextValue } from '../mocks/mock_preview_panel_context'; +import { ALERT_REASON_PREVIEW_BODY_TEST_ID } from './test_ids'; +import { AlertReasonPreview } from './alert_reason_preview'; +import { ThemeProvider } from 'styled-components'; +import { getMockTheme } from '../../../common/lib/kibana/kibana_react.mock'; + +const mockTheme = getMockTheme({ eui: { euiFontSizeXS: '' } }); + +const panelContextValue = { + ...mockContextValue, +}; + +describe('', () => { + it('should render alert reason preview', () => { + const { getByTestId } = render( + + + + + + ); + expect(getByTestId(ALERT_REASON_PREVIEW_BODY_TEST_ID)).toBeInTheDocument(); + }); + + it('should render null is dataAsNestedObject is null', () => { + const contextValue = { + ...mockContextValue, + dataAsNestedObject: null, + }; + const { queryByTestId } = render( + + + + ); + expect(queryByTestId(ALERT_REASON_PREVIEW_BODY_TEST_ID)).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.tsx b/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.tsx new file mode 100644 index 0000000000000..4fd912cbfbeec --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.tsx @@ -0,0 +1,50 @@ +/* + * 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 React, { useMemo } from 'react'; +import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { ALERT_REASON_TITLE } from './translations'; +import { ALERT_REASON_PREVIEW_BODY_TEST_ID } from './test_ids'; +import { usePreviewPanelContext } from '../context'; +import { getRowRenderer } from '../../../timelines/components/timeline/body/renderers/get_row_renderer'; +import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; + +/** + * Alert reason renderer on a preview panel on top of the right section of expandable flyout + */ +export const AlertReasonPreview: React.FC = () => { + const { dataAsNestedObject } = usePreviewPanelContext(); + + const renderer = useMemo( + () => + dataAsNestedObject != null + ? getRowRenderer({ data: dataAsNestedObject, rowRenderers: defaultRowRenderers }) + : null, + [dataAsNestedObject] + ); + + if (!dataAsNestedObject || !renderer) { + return null; + } + + return ( + + +
{ALERT_REASON_TITLE}
+
+ + {renderer.renderRow({ + contextId: 'event-details', + data: dataAsNestedObject, + isDraggable: false, + scopeId: 'global', + })} +
+ ); +}; + +AlertReasonPreview.displayName = 'AlertReasonPreview'; diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/preview/components/test_ids.ts index 1c27fd7472fca..764ec90fd9bdf 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/test_ids.ts @@ -38,3 +38,5 @@ export const RULE_PREVIEW_LOADING_TEST_ID = 'securitySolutionDocumentDetailsFlyoutRulePreviewLoadingSpinner'; export const RULE_PREVIEW_FOOTER_TEST_ID = 'securitySolutionDocumentDetailsFlyoutRulePreviewFooter'; export const RULE_PREVIEW_NAVIGATE_TO_RULE_TEST_ID = 'goToRuleDetails'; +export const ALERT_REASON_PREVIEW_BODY_TEST_ID = + 'securitySolutionDocumentDetailsFlyoutAlertReasonPreviewBody'; diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/translations.ts b/x-pack/plugins/security_solution/public/flyout/preview/components/translations.ts index e3f3b1fd095fb..36bfdd33ea2ca 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/translations.ts +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/translations.ts @@ -31,3 +31,8 @@ export const RULE_PREVIEW_ACTIONS_TEXT = i18n.translate( 'xpack.securitySolution.flyout.documentDetails.rulePreviewActionsSectionText', { defaultMessage: 'Actions' } ); + +export const ALERT_REASON_TITLE = i18n.translate( + 'xpack.securitySolution.flyout.documentDetails.alertReasonTitle', + { defaultMessage: 'Alert reason' } +); diff --git a/x-pack/plugins/security_solution/public/flyout/preview/context.tsx b/x-pack/plugins/security_solution/public/flyout/preview/context.tsx index 521303635c25d..005ef1dcdb258 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/context.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/context.tsx @@ -7,11 +7,15 @@ import React, { createContext, useContext, useMemo } from 'react'; import type { DataViewBase } from '@kbn/es-query'; +import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; +import { SecurityPageName } from '@kbn/security-solution-navigation'; import type { PreviewPanelProps } from '.'; -import { useRouteSpy } from '../../common/utils/route/use_route_spy'; -import { SecurityPageName } from '../../../common/constants'; import { SourcererScopeName } from '../../common/store/sourcerer/model'; import { useSourcererDataView } from '../../common/containers/sourcerer'; +import { useTimelineEventsDetails } from '../../timelines/containers/details'; +import { getAlertIndexAlias } from '../../timelines/components/side_panel/event_details/helpers'; +import { useSpaceId } from '../../common/hooks/use_space_id'; +import { useRouteSpy } from '../../common/utils/route/use_route_spy'; export interface PreviewPanelContext { /** @@ -34,6 +38,10 @@ export interface PreviewPanelContext { * Index pattern for rule details */ indexPattern: DataViewBase; + /** + * An object with top level fields from the ECS object + */ + dataAsNestedObject: Ecs | null; } export const PreviewPanelContext = createContext(undefined); @@ -52,12 +60,21 @@ export const PreviewPanelProvider = ({ ruleId, children, }: PreviewPanelProviderProps) => { + const currentSpaceId = useSpaceId(); + const eventIndex = indexName ? getAlertIndexAlias(indexName, currentSpaceId) ?? indexName : ''; const [{ pageName }] = useRouteSpy(); const sourcererScope = pageName === SecurityPageName.detections ? SourcererScopeName.detections : SourcererScopeName.default; const sourcererDataView = useSourcererDataView(sourcererScope); + const [_, __, ___, dataAsNestedObject] = useTimelineEventsDetails({ + indexName: eventIndex, + eventId: id ?? '', + runtimeMappings: sourcererDataView.runtimeMappings, + skip: !id, + }); + const contextValue = useMemo( () => id && indexName && scopeId @@ -67,9 +84,10 @@ export const PreviewPanelProvider = ({ scopeId, ruleId: ruleId ?? '', indexPattern: sourcererDataView.indexPattern, + dataAsNestedObject, } : undefined, - [id, indexName, scopeId, ruleId, sourcererDataView.indexPattern] + [id, indexName, scopeId, ruleId, sourcererDataView.indexPattern, dataAsNestedObject] ); return ( diff --git a/x-pack/plugins/security_solution/public/flyout/preview/index.tsx b/x-pack/plugins/security_solution/public/flyout/preview/index.tsx index 9bfefb8f257fd..db9f7bb5ba58a 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/index.tsx @@ -10,8 +10,9 @@ import type { FlyoutPanelProps, PanelPath } from '@kbn/expandable-flyout'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { panels } from './panels'; -export type PreviewPanelPaths = 'rule-preview'; +export type PreviewPanelPaths = 'rule-preview' | 'alert-reason-preview'; export const RulePreviewPanel: PreviewPanelPaths = 'rule-preview'; +export const AlertReasonPreviewPanel: PreviewPanelPaths = 'alert-reason-preview'; export const PreviewPanelKey: PreviewPanelProps['key'] = 'document-details-preview'; export interface PreviewPanelProps extends FlyoutPanelProps { diff --git a/x-pack/plugins/security_solution/public/flyout/preview/mocks/mock_preview_panel_context.ts b/x-pack/plugins/security_solution/public/flyout/preview/mocks/mock_preview_panel_context.ts index 4e9f9cc43d8ba..cdfe8ab5307ba 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/mocks/mock_preview_panel_context.ts +++ b/x-pack/plugins/security_solution/public/flyout/preview/mocks/mock_preview_panel_context.ts @@ -5,6 +5,8 @@ * 2.0. */ +import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; +import { mockDataAsNestedObject } from '../../shared/mocks/mock_context'; import type { PreviewPanelContext } from '../context'; /** @@ -16,4 +18,5 @@ export const mockContextValue: PreviewPanelContext = { scopeId: 'scopeId', ruleId: '', indexPattern: { fields: [], title: 'test index' }, + dataAsNestedObject: mockDataAsNestedObject as unknown as Ecs, }; diff --git a/x-pack/plugins/security_solution/public/flyout/preview/panels.tsx b/x-pack/plugins/security_solution/public/flyout/preview/panels.tsx index b9aee26bdd577..e585c58945d9c 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/panels.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/panels.tsx @@ -6,8 +6,9 @@ */ import React from 'react'; +import { AlertReasonPreview } from './components/alert_reason_preview'; import type { PreviewPanelPaths } from '.'; -import { RULE_PREVIEW } from './translations'; +import { ALERT_REASON_PREVIEW, RULE_PREVIEW } from './translations'; import { RulePreview } from './components/rule_preview'; import { RulePreviewFooter } from './components/rule_preview_footer'; @@ -40,4 +41,9 @@ export const panels: PreviewPanelType = [ content: , footer: , }, + { + id: 'alert-reason-preview', + name: ALERT_REASON_PREVIEW, + content: , + }, ]; diff --git a/x-pack/plugins/security_solution/public/flyout/preview/translations.ts b/x-pack/plugins/security_solution/public/flyout/preview/translations.ts index 1db37fbb49bb8..cf359e7900cea 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/translations.ts +++ b/x-pack/plugins/security_solution/public/flyout/preview/translations.ts @@ -11,3 +11,8 @@ export const RULE_PREVIEW = i18n.translate( 'xpack.securitySolution.flyout.documentDetails.rulePreviewPanel', { defaultMessage: 'Rule preview' } ); + +export const ALERT_REASON_PREVIEW = i18n.translate( + 'xpack.securitySolution.flyout.documentDetails.alertReasonPreviewPanel', + { defaultMessage: 'Alert reason preview' } +); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/description.stories.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/description.stories.tsx deleted file mode 100644 index 13fa592c4f7d6..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/right/components/description.stories.tsx +++ /dev/null @@ -1,92 +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 React from 'react'; -import { css } from '@emotion/react'; -import type { Story } from '@storybook/react'; -import { Description } from './description'; -import { RightPanelContext } from '../context'; - -const ruleUuid = { - category: 'kibana', - field: 'kibana.alert.rule.uuid', - values: ['123'], - originalValue: ['123'], - isObjectArray: false, -}; -const ruleDescription = { - category: 'kibana', - field: 'kibana.alert.rule.description', - values: [ - `This is a very long description of the rule. In theory. this description is long enough that it should be cut off when displayed in collapsed mode. If it isn't then there is a problem`, - ], - originalValue: ['description'], - isObjectArray: false, -}; - -export default { - component: Description, - title: 'Flyout/Description', -}; - -const wrapper = (children: React.ReactNode, panelContextValue: RightPanelContext) => ( - -
- {children} -
-
-); -export const Rule: Story = () => { - const panelContextValue = { - dataFormattedForFieldBrowser: [ruleUuid, ruleDescription], - } as unknown as RightPanelContext; - - return wrapper(, panelContextValue); -}; - -export const Document: Story = () => { - const panelContextValue = { - dataFormattedForFieldBrowser: [ - { - category: 'kibana', - field: 'kibana.alert.rule.description', - values: ['This is a description for the document.'], - originalValue: ['description'], - isObjectArray: false, - }, - ], - } as unknown as RightPanelContext; - - return wrapper(, panelContextValue); -}; - -export const EmptyDescription: Story = () => { - const panelContextValue = { - dataFormattedForFieldBrowser: [ - ruleUuid, - { - category: 'kibana', - field: 'kibana.alert.rule.description', - values: [''], - originalValue: ['description'], - isObjectArray: false, - }, - ], - } as unknown as RightPanelContext; - - return wrapper(, panelContextValue); -}; - -export const Empty: Story = () => { - const panelContextValue = {} as unknown as RightPanelContext; - - return wrapper(, panelContextValue); -}; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/description.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/description.test.tsx index 1cf4823d79358..f80d7c1939661 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/description.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/description.test.tsx @@ -8,14 +8,17 @@ import React from 'react'; import { render } from '@testing-library/react'; import { DESCRIPTION_TITLE_TEST_ID, RULE_SUMMARY_BUTTON_TEST_ID } from './test_ids'; -import { DOCUMENT_DESCRIPTION_TITLE, RULE_DESCRIPTION_TITLE } from './translations'; +import { + DOCUMENT_DESCRIPTION_TITLE, + PREVIEW_RULE_DETAILS, + RULE_DESCRIPTION_TITLE, +} from './translations'; import { Description } from './description'; -import { TestProviders } from '../../../common/mock'; import { RightPanelContext } from '../context'; -import { ThemeProvider } from 'styled-components'; -import { getMockTheme } from '../../../common/lib/kibana/kibana_react.mock'; - -const mockTheme = getMockTheme({ eui: { euiColorMediumShade: '#ece' } }); +import { mockGetFieldsData } from '../mocks/mock_context'; +import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; +import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import { PreviewPanelKey } from '../../preview'; const ruleUuid = { category: 'kibana', @@ -41,23 +44,32 @@ const ruleName = { isObjectArray: false, }; -jest.mock('../../../common/lib/kibana'); -jest.mock('../../../common/components/link_to'); +const flyoutContextValue = { + openPreviewPanel: jest.fn(), +} as unknown as ExpandableFlyoutContext; + +const panelContextValue = (dataFormattedForFieldBrowser: TimelineEventsDetailsItem[] | null) => + ({ + eventId: 'event id', + indexName: 'indexName', + scopeId: 'scopeId', + dataFormattedForFieldBrowser, + getFieldsData: mockGetFieldsData, + } as unknown as RightPanelContext); + +const renderDescription = (panelContext: RightPanelContext) => + render( + + + + + + ); describe('', () => { it('should render the component', () => { - const panelContextValue = { - dataFormattedForFieldBrowser: [ruleUuid, ruleDescription, ruleName], - } as unknown as RightPanelContext; - - const { getByTestId } = render( - - - - - - - + const { getByTestId } = renderDescription( + panelContextValue([ruleUuid, ruleDescription, ruleName]) ); expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toBeInTheDocument(); @@ -66,18 +78,8 @@ describe('', () => { }); it('should not render rule preview button if rule name is not available', () => { - const panelContextValue = { - dataFormattedForFieldBrowser: [ruleUuid, ruleDescription], - } as unknown as RightPanelContext; - - const { getByTestId, queryByTestId } = render( - - - - - - - + const { getByTestId, queryByTestId } = renderDescription( + panelContextValue([ruleUuid, ruleDescription]) ); expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toBeInTheDocument(); @@ -86,21 +88,44 @@ describe('', () => { }); it('should render document title if document is not an alert', () => { - const panelContextValue = { - dataFormattedForFieldBrowser: [ruleDescription], - } as unknown as RightPanelContext; - - const { getByTestId } = render( - - - - - - - - ); + const { getByTestId } = renderDescription(panelContextValue([ruleDescription])); expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toHaveTextContent(DOCUMENT_DESCRIPTION_TITLE); }); + + it('should render null if dataFormattedForFieldBrowser is null', () => { + const panelContext = { + ...panelContextValue([ruleUuid, ruleDescription, ruleName]), + dataFormattedForFieldBrowser: null, + } as unknown as RightPanelContext; + + const { container } = renderDescription(panelContext); + + expect(container).toBeEmptyDOMElement(); + }); + + it('should open preview panel when clicking on button', () => { + const panelContext = panelContextValue([ruleUuid, ruleDescription, ruleName]); + + const { getByTestId } = renderDescription(panelContext); + + getByTestId(RULE_SUMMARY_BUTTON_TEST_ID).click(); + + expect(flyoutContextValue.openPreviewPanel).toHaveBeenCalledWith({ + id: PreviewPanelKey, + path: { tab: 'rule-preview' }, + params: { + id: panelContext.eventId, + indexName: panelContext.indexName, + scopeId: panelContext.scopeId, + banner: { + title: PREVIEW_RULE_DETAILS, + backgroundColor: 'warning', + textColor: 'warning', + }, + ruleId: ruleUuid.values[0], + }, + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/reason.stories.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/reason.stories.tsx deleted file mode 100644 index 68cb0b3a35e31..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/right/components/reason.stories.tsx +++ /dev/null @@ -1,45 +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 React from 'react'; -import type { Story } from '@storybook/react'; -import { StorybookProviders } from '../../../common/mock/storybook_providers'; -import { Reason } from './reason'; -import { RightPanelContext } from '../context'; -import { mockDataAsNestedObject, mockDataFormattedForFieldBrowser } from '../mocks/mock_context'; - -export default { - component: Reason, - title: 'Flyout/Reason', -}; - -export const Default: Story = () => { - const panelContextValue = { - dataAsNestedObject: mockDataAsNestedObject, - dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, - } as unknown as RightPanelContext; - - return ( - - - - - - ); -}; - -export const Empty: Story = () => { - const panelContextValue = { - dataFormattedForFieldBrowser: {}, - } as unknown as RightPanelContext; - - return ( - - - - ); -}; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/reason.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/reason.test.tsx index b7050d1df0fa0..3ec854cfbd815 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/reason.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/reason.test.tsx @@ -7,70 +7,85 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { REASON_TITLE_TEST_ID } from './test_ids'; +import { + REASON_DETAILS_PREVIEW_BUTTON_TEST_ID, + REASON_DETAILS_TEST_ID, + REASON_TITLE_TEST_ID, +} from './test_ids'; import { Reason } from './reason'; import { RightPanelContext } from '../context'; -import { mockDataAsNestedObject, mockDataFormattedForFieldBrowser } from '../mocks/mock_context'; -import { euiDarkVars } from '@kbn/ui-theme'; -import { ThemeProvider } from 'styled-components'; +import { mockDataFormattedForFieldBrowser, mockGetFieldsData } from '../mocks/mock_context'; +import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; +import { PreviewPanelKey } from '../../preview'; +import { PREVIEW_ALERT_REASON_DETAILS } from './translations'; -describe('', () => { - it('should render the component', () => { - const panelContextValue = { - dataAsNestedObject: mockDataAsNestedObject, - dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, - } as unknown as RightPanelContext; +const flyoutContextValue = { + openPreviewPanel: jest.fn(), +} as unknown as ExpandableFlyoutContext; - const { getByTestId } = render( - ({ eui: euiDarkVars, darkMode: true })}> - - - - - ); +const panelContextValue = { + eventId: 'event id', + indexName: 'indexName', + scopeId: 'scopeId', + dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, + getFieldsData: mockGetFieldsData, +} as unknown as RightPanelContext; +const renderReason = (panelContext: RightPanelContext = panelContextValue) => + render( + + + + + + ); + +describe('', () => { + it('should render the component', () => { + const { getByTestId } = renderReason(); expect(getByTestId(REASON_TITLE_TEST_ID)).toBeInTheDocument(); }); it('should render null if dataFormattedForFieldBrowser is null', () => { - const panelContextValue = { - dataAsNestedObject: {}, + const panelContext = { + ...panelContextValue, + dataFormattedForFieldBrowser: null, } as unknown as RightPanelContext; - const { container } = render( - - - - ); + const { container } = renderReason(panelContext); expect(container).toBeEmptyDOMElement(); }); - it('should render null if dataAsNestedObject is null', () => { - const panelContextValue = { - dataFormattedForFieldBrowser: [], + it('should render no reason if the field is null', () => { + const panelContext = { + ...panelContextValue, + getFieldsData: () => {}, } as unknown as RightPanelContext; - const { container } = render( - - - - ); + const { getByTestId } = renderReason(panelContext); - expect(container).toBeEmptyDOMElement(); + expect(getByTestId(REASON_DETAILS_TEST_ID)).toBeEmptyDOMElement(); }); - it('should render null if renderer is null', () => { - const panelContextValue = { - dataAsNestedObject: {}, - dataFormattedForFieldBrowser: [], - } as unknown as RightPanelContext; - const { container } = render( - - - - ); + it('should open preview panel when clicking on button', () => { + const { getByTestId } = renderReason(); - expect(container).toBeEmptyDOMElement(); + getByTestId(REASON_DETAILS_PREVIEW_BUTTON_TEST_ID).click(); + + expect(flyoutContextValue.openPreviewPanel).toHaveBeenCalledWith({ + id: PreviewPanelKey, + path: { tab: 'alert-reason-preview' }, + params: { + id: panelContextValue.eventId, + indexName: panelContextValue.indexName, + scopeId: panelContextValue.scopeId, + banner: { + title: PREVIEW_ALERT_REASON_DETAILS, + backgroundColor: 'warning', + textColor: 'warning', + }, + }, + }); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/reason.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/reason.tsx index b6633ac42c46b..b356809917973 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/reason.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/reason.tsx @@ -6,31 +6,71 @@ */ import type { FC } from 'react'; -import React, { useMemo } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; -import { REASON_DETAILS_TEST_ID, REASON_TITLE_TEST_ID } from './test_ids'; -import { ALERT_REASON_TITLE, DOCUMENT_REASON_TITLE } from './translations'; +import React, { useCallback, useMemo } from 'react'; +import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; +import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; +import { getField } from '../../shared/utils'; +import { AlertReasonPreviewPanel, PreviewPanelKey } from '../../preview'; +import { + REASON_DETAILS_PREVIEW_BUTTON_TEST_ID, + REASON_DETAILS_TEST_ID, + REASON_TITLE_TEST_ID, +} from './test_ids'; +import { + ALERT_REASON_DETAILS_TEXT, + ALERT_REASON_TITLE, + DOCUMENT_REASON_TITLE, + PREVIEW_ALERT_REASON_DETAILS, +} from './translations'; import { useBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers'; -import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; -import { getRowRenderer } from '../../../timelines/components/timeline/body/renderers/get_row_renderer'; import { useRightPanelContext } from '../context'; /** * Displays the information provided by the rowRenderer. Supports multiple types of documents. */ export const Reason: FC = () => { - const { dataAsNestedObject, dataFormattedForFieldBrowser } = useRightPanelContext(); + const { eventId, indexName, scopeId, dataFormattedForFieldBrowser, getFieldsData } = + useRightPanelContext(); const { isAlert } = useBasicDataFromDetailsData(dataFormattedForFieldBrowser); + const alertReason = getField(getFieldsData(ALERT_REASON)); - const renderer = useMemo( - () => - dataAsNestedObject != null - ? getRowRenderer({ data: dataAsNestedObject, rowRenderers: defaultRowRenderers }) - : null, - [dataAsNestedObject] + const { openPreviewPanel } = useExpandableFlyoutContext(); + const openRulePreview = useCallback(() => { + openPreviewPanel({ + id: PreviewPanelKey, + path: { tab: AlertReasonPreviewPanel }, + params: { + id: eventId, + indexName, + scopeId, + banner: { + title: PREVIEW_ALERT_REASON_DETAILS, + backgroundColor: 'warning', + textColor: 'warning', + }, + }, + }); + }, [eventId, openPreviewPanel, indexName, scopeId]); + + const viewPreview = useMemo( + () => ( + + + {ALERT_REASON_DETAILS_TEXT} + + + ), + [openRulePreview] ); - if (!dataFormattedForFieldBrowser || !dataAsNestedObject || !renderer) { + if (!dataFormattedForFieldBrowser) { return null; } @@ -38,17 +78,21 @@ export const Reason: FC = () => { -
{isAlert ? ALERT_REASON_TITLE : DOCUMENT_REASON_TITLE}
+
+ {isAlert ? ( + + +
{ALERT_REASON_TITLE}
+
+ {viewPreview} +
+ ) : ( + DOCUMENT_REASON_TITLE + )} +
- - {renderer.renderRow({ - contextId: 'event-details', - data: dataAsNestedObject, - isDraggable: false, - scopeId: 'global', - })} - + {alertReason}
); }; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts index 9e8b112851be6..7d41fe13f9fca 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts @@ -46,6 +46,8 @@ export const DESCRIPTION_DETAILS_TEST_ID = 'securitySolutionDocumentDetailsFlyoutDescriptionDetails'; export const REASON_TITLE_TEST_ID = 'securitySolutionDocumentDetailsFlyoutReasonTitle'; export const REASON_DETAILS_TEST_ID = 'securitySolutionDocumentDetailsFlyoutReasonDetails'; +export const REASON_DETAILS_PREVIEW_BUTTON_TEST_ID = + 'securitySolutionDocumentDetailsFlyoutReasonDetailsPreviewButton'; export const MITRE_ATTACK_TITLE_TEST_ID = 'securitySolutionAlertDetailsFlyoutMitreAttackTitle'; export const MITRE_ATTACK_DETAILS_TEST_ID = 'securitySolutionAlertDetailsFlyoutMitreAttackDetails'; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/translations.ts b/x-pack/plugins/security_solution/public/flyout/right/components/translations.ts index f32e9abb1d48f..a411b0f44054e 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/translations.ts +++ b/x-pack/plugins/security_solution/public/flyout/right/components/translations.ts @@ -45,6 +45,13 @@ export const RULE_SUMMARY_TEXT = i18n.translate( } ); +export const ALERT_REASON_DETAILS_TEXT = i18n.translate( + 'xpack.securitySolution.flyout.documentDetails.alertReasonDetailsText', + { + defaultMessage: 'Show full reason', + } +); + /* About section */ export const ABOUT_TITLE = i18n.translate( @@ -66,6 +73,11 @@ export const PREVIEW_RULE_DETAILS = i18n.translate( { defaultMessage: 'Preview rule details' } ); +export const PREVIEW_ALERT_REASON_DETAILS = i18n.translate( + 'xpack.securitySolution.flyout.documentDetails.previewAlertReasonDetailsText', + { defaultMessage: 'Preview alert reason' } +); + export const DOCUMENT_DESCRIPTION_TITLE = i18n.translate( 'xpack.securitySolution.flyout.documentDetails.documentDescriptionTitle', { diff --git a/x-pack/plugins/security_solution/public/flyout/right/hooks/use_process_data.ts b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_process_data.ts index 72ca71badaf07..ac98ddd1df2b2 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/hooks/use_process_data.ts +++ b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_process_data.ts @@ -6,6 +6,7 @@ */ import { useMemo } from 'react'; +import { ALERT_RULE_NAME, ALERT_RULE_UUID } from '@kbn/rule-data-utils'; import type { GetFieldsData } from '../../../common/hooks/use_get_fields_data'; import { getField } from '../../shared/utils'; import { useRightPanelContext } from '../context'; @@ -14,8 +15,6 @@ const FIELD_USER_NAME = 'process.entry_leader.user.name' as const; const FIELD_USER_ID = 'process.entry_leader.user.id' as const; const FIELD_PROCESS_NAME = 'process.entry_leader.name' as const; const FIELD_START_AT = 'process.entry_leader.start' as const; -const FIELD_RULE_NAME = 'kibana.alert.rule.name' as const; -const FIELD_RULE_ID = 'kibana.alert.rule.uuid' as const; const FIELD_WORKING_DIRECTORY = 'process.group_leader.working_directory' as const; const FIELD_COMMAND = 'process.command_line' as const; @@ -48,8 +47,8 @@ export const useProcessData = () => { userName: getUserDisplayName(getFieldsData), processName: getField(getFieldsData(FIELD_PROCESS_NAME)), startAt: getField(getFieldsData(FIELD_START_AT)), - ruleName: getField(getFieldsData(FIELD_RULE_NAME)), - ruleId: getField(getFieldsData(FIELD_RULE_ID)), + ruleName: getField(getFieldsData(ALERT_RULE_NAME)), + ruleId: getField(getFieldsData(ALERT_RULE_UUID)), workdir: getField(getFieldsData(FIELD_WORKING_DIRECTORY)), command: getField(getFieldsData(FIELD_COMMAND)), }), diff --git a/x-pack/plugins/security_solution/public/flyout/right/mocks/mock_context.ts b/x-pack/plugins/security_solution/public/flyout/right/mocks/mock_context.ts index 6ae872acd45ac..cdc058569d9d3 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/mocks/mock_context.ts +++ b/x-pack/plugins/security_solution/public/flyout/right/mocks/mock_context.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ALERT_RISK_SCORE, ALERT_SEVERITY } from '@kbn/rule-data-utils'; +import { ALERT_REASON, ALERT_RISK_SCORE, ALERT_SEVERITY } from '@kbn/rule-data-utils'; /** * Returns mocked data for field (mock this method: x-pack/plugins/security_solution/public/common/hooks/use_get_fields_data.ts) @@ -22,6 +22,8 @@ export const mockGetFieldsData = (field: string): string[] => { return ['host1']; case 'user.name': return ['user1']; + case ALERT_REASON: + return ['reason']; default: return []; } diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_alert_reason_preview.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_alert_reason_preview.cy.ts new file mode 100644 index 0000000000000..83d2dbee62212 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_alert_reason_preview.cy.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DOCUMENT_DETAILS_FLYOUT_ALERT_REASON_PREVIEW_CONTAINER } from '../../../../screens/expandable_flyout/alert_details_preview_panel_alert_reason_preview'; +import { expandFirstAlertExpandableFlyout } from '../../../../tasks/expandable_flyout/common'; +import { clickAlertReasonButton } from '../../../../tasks/expandable_flyout/alert_details_right_panel_overview_tab'; +import { cleanKibana } from '../../../../tasks/common'; +import { login, visit } from '../../../../tasks/login'; +import { createRule } from '../../../../tasks/api_calls/rules'; +import { getNewRule } from '../../../../objects/rule'; +import { ALERTS_URL } from '../../../../urls/navigation'; +import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; +import { tag } from '../../../../tags'; + +describe( + 'Alert details expandable flyout rule preview panel', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + const rule = getNewRule(); + + beforeEach(() => { + cleanKibana(); + login(); + createRule(rule); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + expandFirstAlertExpandableFlyout(); + clickAlertReasonButton(); + }); + + describe('alert reason preview', () => { + it('should display alert reason preview', () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_ALERT_REASON_PREVIEW_CONTAINER).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_ALERT_REASON_PREVIEW_CONTAINER).should('be.visible'); + }); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts index 2cdf95746dcfa..050463b70ae50 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts @@ -111,7 +111,8 @@ describe( cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE) .should('be.visible') - .and('have.text', 'Alert reason'); + .and('contain.text', 'Alert reason') + .and('contain.text', 'Show full reason'); cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS) .should('be.visible') .and('contain.text', rule.name); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel_alert_reason_preview.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel_alert_reason_preview.ts new file mode 100644 index 0000000000000..37db919da75ab --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel_alert_reason_preview.ts @@ -0,0 +1,13 @@ +/* + * 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 { ALERT_REASON_PREVIEW_BODY_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/preview/components/test_ids'; +import { getDataTestSubjectSelector } from '../../helpers/common'; + +export const DOCUMENT_DETAILS_FLYOUT_ALERT_REASON_PREVIEW_CONTAINER = getDataTestSubjectSelector( + ALERT_REASON_PREVIEW_BODY_TEST_ID +); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts index dc7e3fdd1020e..ebfb40a3091f5 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts @@ -38,6 +38,7 @@ import { ANALYZER_PREVIEW_CONTENT_TEST_ID, SESSION_PREVIEW_CONTENT_TEST_ID, INSIGHTS_PREVALENCE_VALUE_TEST_ID, + REASON_DETAILS_PREVIEW_BUTTON_TEST_ID, } from '@kbn/security-solution-plugin/public/flyout/right/components/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; @@ -59,6 +60,8 @@ export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE = getDataTestSubjectSelector(REASON_TITLE_TEST_ID); export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS = getDataTestSubjectSelector(REASON_DETAILS_TEST_ID); +export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_OPEN_ALERT_REASON_PREVIEW_BUTTON = + getDataTestSubjectSelector(REASON_DETAILS_PREVIEW_BUTTON_TEST_ID); export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE = getDataTestSubjectSelector( MITRE_ATTACK_TITLE_TEST_ID ); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_overview_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_overview_tab.ts index c87a3c2afb9fe..b94a8be090fa4 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_overview_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_overview_tab.ts @@ -20,6 +20,8 @@ import { DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_OPEN_RULE_PREVIEW_BUTTON, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_RESPONSE_SECTION_HEADER, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_OPEN_ALERT_REASON_PREVIEW_BUTTON, } from '../../screens/expandable_flyout/alert_details_right_panel_overview_tab'; /* About section */ @@ -129,3 +131,17 @@ export const clickRuleSummaryButton = () => { .click(); }); }; + +/** + * Click `Show full reason` button to open alert reason preview panel + */ +export const clickAlertReasonButton = () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE) + .should('be.visible') + .within(() => { + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_OPEN_ALERT_REASON_PREVIEW_BUTTON) + .should('be.visible') + .click(); + }); +}; From d725c289af3cf4c6a563d2292b8029afee4eab0e Mon Sep 17 00:00:00 2001 From: Juan Pablo Djeredjian Date: Wed, 16 Aug 2023 14:45:41 +0200 Subject: [PATCH 11/11] [Security Solution] Fix flaky test: `detection_rules/bulk_edit_rules_actions.cy.ts` (#163698) Fixes: https://github.com/elastic/kibana/issues/154721 ## Summary - Fixes flaky test: `x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts` - Test title: `Detection rules, bulk edit of rule actions` ## Details For: `Detection rules, bulk edit of rule actions - Restricted action privileges - User with no privileges can't add rule actions` - Since this test logs in with a user with missing privileges, the "Missing privileges" callout is shown at the top of the Rules Table. The `selectNumberOfRules();` command selects rules one by one by clicking on their checkboxes. However, flakiness was caused when the callout was rendered while the selection of the rules was happening, causing a layout shift that caused the selection of a checkbox to lose focus, and not being able to be checked. This was solved by waiting the callout to be rendered before the selection of rules start, with the new `waitForCallOutToBeShown`method. For: `Detection rules, bulk edit of rule actions - All actions privileges - before/beforeEach Clause` - Tests were failing in the `beforeEach` clause because the first test, mentioned above, would be logged in with a `ROLES.hunter_no_actions` role, and logging in with a user with permissions happened in a `before` clause instead of a `beforeEach` clause. This caused the rest of the suite to continue with a role without permissions, and the setup of the second test would fail as the API requests done would fail with `401`. Moving the initial logging-in from a `before` clause to a `beforeEach` clause solved this issue. For: `Detection rules, bulk edit of rule actions - All actions privileges - Add a rule action to rules (existing connector)` - This flakiness was extremely rare, but could be reproduced after about 400 iterations. It was caused by a similar reason as the first case above: while rules were being selected one by one, the table would auto refresh and focus would be lost from the checkbox that was about to be selected. This aws fixed by disabling autorefresh in the setup. ### Other changes - Prevents the installation of `security_detection_engine` package and creates mock rules instead. - Creates the `waitForCallOutToBeShown` method and moves the callout IDs spread across different files to a a single file where they are exported from. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- ...ts_detection_callouts_index_outdated.cy.ts | 8 ++-- .../missing_privileges_callout.cy.ts | 9 ++-- .../authorization/all_rules_read_only.cy.ts | 3 +- .../bulk_edit_rules_actions.cy.ts | 41 +++++++++++++++---- .../read_only.cy.ts | 3 +- .../cypress/tasks/common/callouts.ts | 3 ++ 6 files changed, 48 insertions(+), 19 deletions(-) diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts index 59aa3a5abe793..1a1b47e925c91 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts @@ -15,7 +15,11 @@ import { PAGE_TITLE } from '../../screens/common/page'; import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../tasks/login'; import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; import { createRule, deleteCustomRule } from '../../tasks/api_calls/rules'; -import { getCallOut, waitForCallOutToBeShown } from '../../tasks/common/callouts'; +import { + getCallOut, + NEED_ADMIN_FOR_UPDATE_CALLOUT, + waitForCallOutToBeShown, +} from '../../tasks/common/callouts'; const loadPageAsPlatformEngineerUser = (url: string) => { login(ROLES.soc_manager); @@ -31,8 +35,6 @@ describe( 'Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', { tags: tag.ESS }, () => { - const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; - before(() => { // First, we have to open the app on behalf of a privileged user in order to initialize it. // Otherwise the app will be disabled and show a "welcome"-like page. diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/missing_privileges_callout.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/missing_privileges_callout.cy.ts index 4ca60eebad297..767b2ecbdd5c2 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/missing_privileges_callout.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/missing_privileges_callout.cy.ts @@ -15,7 +15,12 @@ import { PAGE_TITLE } from '../../screens/common/page'; import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../tasks/login'; import { goToRuleDetails } from '../../tasks/alerts_detection_rules'; import { createRule, deleteCustomRule } from '../../tasks/api_calls/rules'; -import { getCallOut, waitForCallOutToBeShown, dismissCallOut } from '../../tasks/common/callouts'; +import { + getCallOut, + waitForCallOutToBeShown, + dismissCallOut, + MISSING_PRIVILEGES_CALLOUT, +} from '../../tasks/common/callouts'; const loadPageAsReadOnlyUser = (url: string) => { login(ROLES.reader); @@ -39,8 +44,6 @@ const waitForPageTitleToBeShown = () => { }; describe('Detections > Callouts', { tags: tag.ESS }, () => { - const MISSING_PRIVILEGES_CALLOUT = 'missing-user-privileges'; - before(() => { // First, we have to open the app on behalf of a privileged user in order to initialize it. // Otherwise the app will be disabled and show a "welcome"-like page. diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/authorization/all_rules_read_only.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/authorization/all_rules_read_only.cy.ts index 62f484b69427a..bd8c5743d37b2 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/authorization/all_rules_read_only.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/authorization/all_rules_read_only.cy.ts @@ -22,12 +22,11 @@ import { dismissCallOut, getCallOut, waitForCallOutToBeShown, + MISSING_PRIVILEGES_CALLOUT, } from '../../../../tasks/common/callouts'; import { login, visitWithoutDateRange } from '../../../../tasks/login'; import { SECURITY_DETECTIONS_RULES_URL } from '../../../../urls/navigation'; -const MISSING_PRIVILEGES_CALLOUT = 'missing-user-privileges'; - describe('All rules - read only', { tags: tag.ESS }, () => { before(() => { cleanKibana(); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts index d6000c671fb86..3b3755dc66d3f 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts @@ -7,6 +7,11 @@ import type { RuleActionArray } from '@kbn/securitysolution-io-ts-alerting-types'; import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { + MISSING_PRIVILEGES_CALLOUT, + waitForCallOutToBeShown, +} from '../../../../../tasks/common/callouts'; +import { createRuleAssetSavedObject } from '../../../../../helpers/rules'; import { tag } from '../../../../../tags'; import { @@ -34,6 +39,7 @@ import { waitForRulesTableToBeLoaded, selectNumberOfRules, goToEditRuleActionsSettingsOf, + disableAutoRefresh, } from '../../../../../tasks/alerts_detection_rules'; import { waitForBulkEditActionToFinish, @@ -57,28 +63,28 @@ import { getMachineLearningRule, getNewTermsRule, } from '../../../../../objects/rule'; -import { excessivelyInstallAllPrebuiltRules } from '../../../../../tasks/api_calls/prebuilt_rules'; +import { + createAndInstallMockedPrebuiltRules, + excessivelyInstallAllPrebuiltRules, + preventPrebuiltRulesPackageInstallation, +} from '../../../../../tasks/api_calls/prebuilt_rules'; const ruleNameToAssert = 'Custom rule name with actions'; const expectedNumberOfCustomRulesToBeEdited = 7; -// 7 custom rules of different types + 3 prebuilt. +// 7 custom rules of different types + 2 prebuilt. // number of selected rules doesn't matter, we only want to make sure they will be edited an no modal window displayed as for other actions -const expectedNumberOfRulesToBeEdited = expectedNumberOfCustomRulesToBeEdited + 3; +const expectedNumberOfRulesToBeEdited = expectedNumberOfCustomRulesToBeEdited + 2; const expectedExistingSlackMessage = 'Existing slack action'; const expectedSlackMessage = 'Slack action test message'; -// TODO: Fix flakiness and unskip https://github.com/elastic/kibana/issues/154721 -describe.skip( +describe( 'Detection rules, bulk edit of rule actions', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { - before(() => { + beforeEach(() => { cleanKibana(); login(); - }); - - beforeEach(() => { deleteAlertsAndRules(); deleteConnectors(); cy.task('esArchiverResetKibana'); @@ -111,12 +117,27 @@ describe.skip( createRule(getNewRule({ saved_id: 'mocked', rule_id: '7' })); createSlackConnector(); + + // Prevent prebuilt rules package installation and mock two prebuilt rules + preventPrebuiltRulesPackageInstallation(); + + const RULE_1 = createRuleAssetSavedObject({ + name: 'Test rule 1', + rule_id: 'rule_1', + }); + const RULE_2 = createRuleAssetSavedObject({ + name: 'Test rule 2', + rule_id: 'rule_2', + }); + + createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2] }); }); context('Restricted action privileges', () => { it("User with no privileges can't add rule actions", () => { login(ROLES.hunter_no_actions); visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL, ROLES.hunter_no_actions); + waitForCallOutToBeShown(MISSING_PRIVILEGES_CALLOUT, 'primary'); waitForRulesTableToBeLoaded(); selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); @@ -129,8 +150,10 @@ describe.skip( context('All actions privileges', () => { beforeEach(() => { + login(); visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); waitForRulesTableToBeLoaded(); + disableAutoRefresh(); }); it('Add a rule action to rules (existing connector)', () => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/read_only.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/read_only.cy.ts index 25b9d2e34fe2e..b11d3de105b83 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/read_only.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/read_only.cy.ts @@ -17,12 +17,11 @@ import { dismissCallOut, getCallOut, waitForCallOutToBeShown, + MISSING_PRIVILEGES_CALLOUT, } from '../../../../tasks/common/callouts'; import { login, visitWithoutDateRange } from '../../../../tasks/login'; import { EXCEPTIONS_URL } from '../../../../urls/navigation'; -const MISSING_PRIVILEGES_CALLOUT = 'missing-user-privileges'; - describe('Shared exception lists - read only', { tags: tag.ESS }, () => { before(() => { cy.task('esArchiverResetKibana'); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/common/callouts.ts b/x-pack/test/security_solution_cypress/cypress/tasks/common/callouts.ts index c65a29b8aa750..802faf821f8da 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/common/callouts.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/common/callouts.ts @@ -7,6 +7,9 @@ import { callOutWithId, CALLOUT_DISMISS_BTN } from '../../screens/common/callouts'; +export const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules'; +export const MISSING_PRIVILEGES_CALLOUT = 'missing-user-privileges'; + export const getCallOut = (id: string, options?: Cypress.Timeoutable) => { return cy.get(callOutWithId(id), options); };